/ / F # Radzenie sobie z Null Records zwrócone z Database - .net, f #, servicestack.redis

F # Radzenie sobie z Null Records zwrócone z Database - .net, f #, servicestack.redis

Podczas pobierania unikatowych pozycji z bazy danych muszę uwzględnić scenariusz, gdy nie ma danych dla identyfikatora dostarczonego przez klienta. Na przykład identyfikator jest nieprawidłowy lub dane w pamięci podręcznej wygasły.

Szczególna biblioteka klienta DB, której używam w tym przykładzie, to ServiceStack.Redis, ale myślę, że zasada dotyczy dowolnej biblioteki CLR.

Zdefiniowałem strukturę danych za pomocą typu rekordu pokazanego poniżej. Teraz, kiedy używam biblioteki klienta do pobierania danych dla klucza, który nie istnieje w bazie danych null wartość jest zwracana. Tego oczekuję i cieszę się z tego. Problem polega na tym, że kompilator F # nie pozwoli mi dopasować wzorca do tego scenariusza - nawet jeśli może się to zdarzyć w czasie wykonywania!

type MyRecordType = { id:int; name:string; desc:string }

let redis = new RedisClient("localhost")
let nullCheck =
let item = redis.Get<MyRecordType> "xxx"
// it is possible that item is null
// but the compiler will not permit the match
match item with
| null -> None
| _ -> Some item

Biblioteka klienta Redis zawiera "ContainsKey"metoda zwracająca wartość logiczną, której mógłbym użyć jako pierwsza, ale dwa wywołania do bazy danych są tutaj niepotrzebne. Odwrotnie jest użycie klasy zdefiniowanej w projekcie C # jako struktury danych, ale wiąże się to ze zbyt dużym narzutem. Ten atrybut również nie zezwala na dopasowanie null.

Chciałbym wiedzieć, jaką konwencję powinienem zastosować, aby poradzić sobie z tym scenariuszem, ponieważ wydaje się, że jest to bardzo powszechny problem?

Odpowiedzi:

4 dla odpowiedzi № 1

Niestety nie możesz tego użyć AllowNullLiteral w rekordach. W rezultacie najlepszym rozwiązaniem jest utworzenie wartości pustej i sprawdzenie równości

if item = Operators.Unchecked.defaultof<_> then None else Some(item)

3 dla odpowiedzi № 2

Też znalazłem Ten artykuł co wykorzystuje boks. Myślę, że czyta się nieco czystsze:

if (box item = null) then None else Some item

3 dla odpowiedzi nr 3

Myślę, że może to być trochę lepsze niżinne opcje, które widziałem Operator F # równa jest bardzo potężny, ale jest też całkiem przesadny, kiedy naprawdę chcesz wiedzieć, czy masz referencję zerową.

if obj.ReferenceEquals(item, null) then None else Some item

To może nie mieć znaczenia, chyba że robisz los porównań, ale jest prawdziwa różnica:

> for i = 1 to 100000000 do bar = null |> ignore;;
Real: 00:00:00.233, CPU: 00:00:00.234, GC gen0: 0, gen1: 0, gen2: 0
val it : unit = ()
> for i = 1 to 100000000 do obj.ReferenceEquals(bar, null) |> ignore;;
Real: 00:00:00.030, CPU: 00:00:00.031, GC gen0: 0, gen1: 0, gen2: 0