-1

I have a method that will take data from a DB and I would like to return a single object back.

However the following code will return null back.

I already verified that the dt coming in contains 1 record.

This method works if I change the return type from an object to a list of objects.

I am tying to understand why in this case and why I can't return just a single object.

    public PersonObj GetPersonInformation(string personName)
    {
        DataTable dt = _oracle.GetPersonInformation(personName);
        var aPerson = dt.AsEnumerable().Select(x => 
                    new PersonObj
                    {
                        FirstName = x.Field<string>("FIRST_NAME"),
                        LastName = x.Field<string>("LAST_NAME"),
                        PhoneNumber = x.Field<string>("PHONE_NUMBER")
                    }).ToList().Take(1);

        return aPerson as PersonObj;
    }
John Doe
  • 3,053
  • 17
  • 48
  • 75
  • 2
    From linked duplicate: "Finally, the difference between First() and Take() is that First() returns the element itself, while Take() returns a sequence of elements that contains exactly one element. (If you pass 1 as the parameter)." – Alexei Levenkov Jan 28 '16 at 19:14
  • Side note: it is expected that author of the question performs some basic investigation (i.e. reads MSDN articles on each method used in the question for C#), not doing so (or not demonstrating results) does not reflect well on author and also may trigger a lot of downvotes on the post itself (even if post did nothing wrong - they can't fix themselves) – Alexei Levenkov Jan 28 '16 at 19:17

3 Answers3

2

Your problem is because Take returns an IEnumerable. This is because you can specify the amount to take. What would happen, for example, if you did this?

    public PersonObj GetPersonInformation(string personName, int take)
        {
            DataTable dt = _oracle.GetPersonInformation(personName);
            return dt.AsEnumerable().Select(x => 
                        new PersonObj
                        {
                            FirstName = x.Field<string>("FIRST_NAME"),
                            LastName = x.Field<string>("LAST_NAME"),
                            PhoneNumber = x.Field<string>("PHONE_NUMBER")
                        }).ToList().Take(take);

        }

You might ask for (and get) one, but you might ask for more. This shows why you're getting the error: Take(1) returns an IEnumerable with 1 element, not a single element itself.

If you just want the first one, you can call First() instead.

DrewJordan
  • 5,266
  • 1
  • 25
  • 39
  • Use FirstOrDefault(), not First(), to avoid possible exceptions – Joe Jan 28 '16 at 19:16
  • 2
    @Joe that's your opinion... No reason not to use `First` if you know for sure there is an element to return, or if you'd rather an exception get thrown. – DrewJordan Jan 28 '16 at 19:18
1

Instead of Take(1), do First() or FirstOrDefault()

Take(n) returns an IEnumerable of Count n (in your case, an IEnumerable of Count 1) whereas First() returns the first object in the IEnumerable.

Frank Bryce
  • 8,076
  • 4
  • 38
  • 56
  • That worked, but why can't I use Take(1)? – John Doe Jan 28 '16 at 19:13
  • 2
    because Take(1) does not return one object, it returns a list containing one object. (btw, I mean list in the generic sense, not List) – Joe Jan 28 '16 at 19:17
  • @JDS See my edit. `Take()` is a general method that will return an `IEnumerable` of however long you give it. For this reason, it's consistent to return an `IEnumerable` of count 1 instead of the first element. – Frank Bryce Jan 28 '16 at 19:20
1

Have you tried using FirstOrDefault() instead of Take(1)? That should allow you to specify that you expect only a single result. I believe the reason you are having a problem with the datatype is due to the ToList() and Take() call, which can return more than one object.

BeckySmith
  • 11
  • 2