2

In entity framework 6 database first when using stored procedures I simply do all of my left outer joins and inner joins and select any specific navigation properties in my query with names that match my extended property names. Then in my data library I extend the auto-generated classes with any Navigation properties that the stored procedure is setting so I can do something like this: (in this example I simply set the CustomerName property which is a property I manually added to CustomerContact in my extension class (i.e.)

public partial class CustomerContact {
   public string CustomerName { get; set; }
}

public static IEnumerable<CustomerContact> GetList(int customerId = null)
{
    using (var context = new LowthersContext())
    {
        var procList = context.GetCustomerContactsProc(customerId);
        var ccList = (from cc in procList
                       select new Material()
                      {
                          Id = cc.Id,
                          FirstName = cc.FirstName,
                          LastName = cc.LastName,
                          Email = cc.Email

                          // navigation properties from joins
                          CustomerName = cc.CustomerName // this property is added in partial class
                      }).ToList();
        return ccList;
    }
}

The above works fine, and it is bit of an oldschool technique using stored procedures, but I want to convert some of my simple stored procs to use Linq to SQL instead. Here is my attempt and I am getting an error:

The entity or complex type 'Data Model.CustomerContact' cannot be constructed in a LINQ to Entities query.

var cList = (from cc in context.CustomerContacts
               join c in context.Customers on cc.CustomerId equals c.Id
               join cl in context.CustomerLocations on c.LocationId = cl.Id
               where (customerId == null || cc.CustomerId == customerId)
               select new CustomerContact
               {
                   Id = cc.Id,
                   FirstName = cc.FirstName,
                   LastName = cc.LastName,
                   Email = cc.Email,

                   // navigation properties
                   CustomerName = c.Name
                   ContactLocationName = cl.LocationName
               }).ToList();
return cList;

I really want to ignore the navigation properties that Entity Framework auto generates for me and set only the individual properties as needed rather than whole objects for performance.

Gert Arnold
  • 105,341
  • 31
  • 202
  • 291
JTunney
  • 914
  • 1
  • 15
  • 46
  • You can only do this if you introduce a non-entity class like `CustomerContactDto` (or `CustomerContactViewModel`, etc.). – Gert Arnold May 16 '15 at 14:49
  • Alright, otherwise I have to lazy load using .include and get rid of all of these joins correct? My only concern when going that route is: Lets say I want to do a left outer join on OrderDetail.MaterialId=Material.Id and if there is a match return Material.Description, otherwise return OrderDetail.Description. Would I have to do logic like this in my actual code? I am used to simply taking care of it in my SELECT in a stored proc and returning something like MaterialDescription as a string property in my OrderDetail class. – JTunney May 16 '15 at 15:00
  • First let me clarify that "LINQ-to-SQL" does not apply here, that's an other, although similar, OR/Mappper. If by "actual code" you mean that you have to write the logic yourself instead of having it generated or inferred somehow, yes, you have. I suppose that this has to do with EF's change tracking. It only trusts entities it constructs itself. It can't guarantee correct tracking of entities that have been "tampered with" during construction. I see your point though. It would be nice if this was possible. – Gert Arnold May 16 '15 at 15:21
  • So I guess the best option for me would be to ignore all of the cool virtual properties that EF is setting up for me automatically and create a Model layer with Dtos that only contain flat properties. Then in my queries populate my flat properties. Performance will be best and doing things such as that If statement will be easy so that when my App needs MaterialDescription it will automatically be the correct value. Does this seem like the best route for me as long as I don't care about virtual navigation properties being populated when doing a Find() and GetList() etc..?? – JTunney May 16 '15 at 15:27
  • I am pretty sure if I go this route I would want to use AutoMapper to map from the EF classes to my Dto classes. Does this map sense? – JTunney May 16 '15 at 15:27
  • Yes, AutoMapper certainly makes sense. But abandoning navigation properties doesn't. You can always use things like `Contact.CustomerLocation.LocationName` to get to specific properties only. And AutoMapper can do a little magic called [flattening](https://automapper.codeplex.com/wikipage?title=Flattening). – Gert Arnold May 16 '15 at 15:35
  • Make sure you use the [`Project.To` API](http://stackoverflow.com/a/12365931/861716). – Gert Arnold May 16 '15 at 15:37
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/77971/discussion-between-jtunney-and-gert-arnold). – JTunney May 16 '15 at 15:41
  • Sorry, I'm about to leave. I wouldn't mind summarizing this in an answer later. – Gert Arnold May 16 '15 at 15:45

0 Answers0