2

While trying a sem-complex query to display some ListView content on the page I got stuck on the famous "Only parameterless contstructor and initializers are supported in LINQ to Entities" error.

Here is the code I used ... I can't find a place where I initialized something inside the query with parameters ....

protected void ArtistsList()
{
    Guid cat1 = new Guid("916ec8ae-8336-43b1-87c0-8536b2676560");
    Guid cat2 = new Guid("92f2a07f-0570-4521-870a-bf898d1e92d6");

    var memberOrders = (from o in DataContext.OrderSet
                        where o.Status == 1 || o.Status == 0
                        select o.ID);

    var memberOrderDetails = (from o in DataContext.OrderDetailSet
                              where memberOrders.Any(f => f == o.Order.ID)
                              select o.Product.ID );

    var inventoryItems = (from i in DataContext.InventoryItemSet
                          select i.Inventory.Product.ID);

    var products = (from p in DataContext.ProductSet
                    join m in DataContext.ContactSet on p.ManufacturerID equals m.ID
                    where p.Active == true
                       && p.ShowOnWebSite == true
                       && p.Category.ID != cat1
                       && p.Category.ID != cat2
                       && p.AvailableDate <= DateTime.Today
                       && (p.DiscontinuationDate == null || p.DiscontinuationDate >= DateTime.Today)
                       && memberOrderDetails.Any(f => f != p.ID)
                       && inventoryItems.Any(f => f == p.ID)
                    select new { ContactID = m.ID, ContactName = m.Name });

    artistsRepeater.DataSource = products;
    artistsRepeater.DataBind();

    Response.Write("PRODUCT COUNT: " + products.Count());
}

The error itself pops on the line artistsRepeater.DataSource = products;

I tried to comment the lines && memberOrderDetails.Any(f => f != p.ID) and && inventoryItems.Any(f => f == p.ID) , still doesn't change anything

Any hints ?

[edit]

With LINQpad, it works with the join but with it is bugging on the commented line

(from p in Products
join m in Members on p.ManufacturerID.Value equals m.ID
where p.Active == true
&& p.ShowOnWebSite == true
&& p.AvailableDate <= DateTime.Today
&& (p.DiscontinuationDate == null || p.DiscontinuationDate >= DateTime.Today)
//&& (from od in MemberOrderDetails where (from mo in MemberOrders where mo.Status == 1 || mo.Status == 0 select mo.ID).Any(f => f == od.ID) select od.Product.ID)
&& (from inv in InventoryItems select inv.Inventory.ProductID).Any(i => i.Value == p.ID)
select m).Distinct()

[edit-2]

It seems that this query in LINQpad is ok :

(from p in Products
join m in Members on p.ManufacturerID.Value equals m.ID
where p.Active == true
&& p.ShowOnWebSite == true
&& p.AvailableDate <= DateTime.Today
&& (p.DiscontinuationDate == null || p.DiscontinuationDate >= DateTime.Today)
&& !(from od in MemberOrderDetails where (from mo in MemberOrders where mo.Status == 1 || mo.Status == 0 select mo).Any(f => f.ID == od.ID) select od.Product.ID).Any(i => i == p.ID)
&& (from inv in InventoryItems select inv.Inventory.ProductID).Any(i => i.Value == p.ID) 
select m)
Erick
  • 5,969
  • 10
  • 42
  • 61
  • would help to know which one of the queries throws the error, although i suspect its `products` – Stan R. Jan 19 '10 at 19:01
  • Does the problem go away if you remove the `memberOrderDetails.Any` and `inventoryItems.Any` bits? – Craig Stuntz Jan 19 '10 at 19:09
  • @Stan R., yep it's on `artistsRepeater.DataSource = products;`, @Craig, I tried to comment/remove them, I still have the same error – Erick Jan 19 '10 at 19:13
  • after the var products line, do a look at the products var and see what's in there. Does it blow up when you expand it? I'm guessing it does – Tad Donaghe Jan 19 '10 at 19:15
  • What is artistsRepeater? What type? – Tad Donaghe Jan 19 '10 at 19:16
  • @Erick: That does not necessarily mean that `products` is the ultimate offender. Remember that queries are deferred. So `memberOrders`, `memberOrderDetails` and `inventoryItems` are not executed until the data bind occurs. They are potentially offenders too. – jason Jan 19 '10 at 19:17
  • I don't trust ASP.NET to turn a Queryable into a collection. So I'd probably use artistsRepeater.DataSource = products.ToArray() – Frank Schwieterman Jan 19 '10 at 19:17
  • 1
    Hum something weird, it seems that when I remove the "join" part it doesn't blow up at all ?! the values returned are of course not the right ones but still .... – Erick Jan 19 '10 at 19:18
  • My next step would probably be to comment out bits of the `where` one at a time to make the problem go away. BTW, LINQPad is really helpful for this; you won't have to recompile your app to experiment that way. – Craig Stuntz Jan 19 '10 at 19:19
  • What are the types of `ProductSet.ManufacturerID` and `ContactSet.ID`? – jason Jan 19 '10 at 19:20
  • @Jason they are Guids, @Craig not sure it would behave correctly, isn't LINQpad more LINQ-to-sql oriented ? – Erick Jan 19 '10 at 19:21
  • @Craig Stuntz: I'm not sure if LINQPad would be helpful here. I'm not too familiar with it, but I don't think it would run these queries as if they were LINQ to Entities queries. Keep in mind that LINQ to Entities is a lot harder about server/client boundaries than, say, LINQ to SQL is. Does LINQPad really allow you to distinguish between these environments? – jason Jan 19 '10 at 19:21
  • @Erick: Well, `System.Guid` does not have a parameterless constructor so that is your issue. – jason Jan 19 '10 at 19:22
  • LINQPad works fine with LINQ to Entities. And no, it doesn't fake it with L2S; it uses your entity model. http://www.linqpad.net/EntityFramework.aspx – Craig Stuntz Jan 19 '10 at 19:23
  • Jason, it's legal to use literal GUIDs in L2E, and you are allowed to compare them, too. – Craig Stuntz Jan 19 '10 at 19:25
  • 1
    Hum, it seems that p.ManufacturerID is a Guid? (nullable) so I did a p.ManufacturerID.Value ... still have the error – Erick Jan 19 '10 at 19:29
  • Anything special we should know about `Contact`? Did you extend it with a partial class? – Craig Stuntz Jan 19 '10 at 19:35
  • @Craig, as I know of the 3rd party developper created it with automated tools with VS – Erick Jan 19 '10 at 19:37
  • 1
    OK, get LINQPad. Point it at your entity model using the instructions in the link I gave. Will take 10 minutes max to do. Now start writing queries. Start with `from c in ContactSet select c` (you don't use a context reference in LINQPad; just specify the entity set. Make the query progressively more complicated until it fails. – Craig Stuntz Jan 19 '10 at 19:40
  • @Craig yep trying ATM be back with some more details... – Erick Jan 19 '10 at 19:45
  • @Craig, with LInQpad it works but it bugs on the commented line here ... quite weird I must say. On visual studio it doesn't work at all when I comment the line it's still buggy with the join part. – Erick Jan 19 '10 at 20:37
  • I edited with a LINQpad query that *seems* to work here. – Erick Jan 19 '10 at 21:37

3 Answers3

1

The most likely culprit is:

select new { ContactID = m.ID, ContactName = m.Name }

This is because anonymous types do not have parameterless constructors. What's odd about that is that anonymous types are de riguer in LINQ to Entities. I just don't see any other line that could be offending.

First try removing that line and see if the error goes away. At least we'll know if it's that line or not. Then we can focus on figuring out why.

Edit: What are the types of OrderSet.ID, Product.ID and Order.ID and ContactSet.ID? Are any of them Guid and implicitly the Guid constructor is being called?

jason
  • 236,483
  • 35
  • 423
  • 525
  • Okay, so we are near certain it's not that line? Ugh. This is definitely mysterious. – jason Jan 19 '10 at 19:09
  • @Craig Stuntz: I understand that. Hence the statement "anonymous types are de riguer in LINQ to Entities." – jason Jan 19 '10 at 19:10
  • 1
    What are the types of `OrderSet.ID`, `Product.ID` and `Order.ID`? Are any of them `Guid` and implicitly the `System.Guid` constructor is being called? – jason Jan 19 '10 at 19:15
  • I'm interested in seeing if he can do a watch on products and expand it and see the entire collection... – Tad Donaghe Jan 19 '10 at 19:16
  • @Jason all of them are guid you are right. For the constructor part tho I can't say. – Erick Jan 19 '10 at 19:19
  • @Terry, can't debug the website, I'm based on a 3rd party ERP that can't be compiled/transformed in web application :/ – Erick Jan 19 '10 at 19:19
  • How about doing a Response.Write and try to spit out a list of the product IDs. That would see if we're blowing up for sure on products – Tad Donaghe Jan 19 '10 at 19:25
  • @Jason tried to only select m and still it blows. Tho I already worked with L2E with Guid and they seemed to work ... – Erick Jan 19 '10 at 19:29
1

OK, this is subtle, but what if you change your LINQPad query from:

           (from p in Products
            join m in Members 
                on p.ManufacturerID.Value equals m.ID
            where p.Active == true
                && p.ShowOnWebSite == true
                && p.AvailableDate <= DateTime.Today
                && (p.DiscontinuationDate == null || p.DiscontinuationDate >= DateTime.Today)
                && (from od in MemberOrderDetails 
                    where (from mo in MemberOrders 
                           where mo.Status == 1 || mo.Status == 0 
                           select mo.ID).Any(f => f == od.ID) 
                    select od.Product.ID)
                && (from inv in InventoryItems 
                    select inv.Inventory.ProductID).Any(i => i.Value == p.ID)

...to:

           (from p in Products
            join m in Members 
                on p.ManufacturerID.Value equals m.ID
            where p.Active == true
                && p.ShowOnWebSite == true
                && p.AvailableDate <= DateTime.Today
                && (p.DiscontinuationDate == null || p.DiscontinuationDate >= DateTime.Today)
                && (from od in MemberOrderDetails 
                    where (from mo in MemberOrders 
                           where mo.Status == 1 || mo.Status == 0 
                           select mo).Any(f => f.ID == od.ID)          // NOTE!
                    select od.Product.ID)
                && (from inv in InventoryItems 
                    select inv.Inventory.ProductID).Any(i => i.Value == p.ID)

Why? I think type inference might be doing you wrong here. I've seen a similar thing with DateTimes.

Craig Stuntz
  • 125,891
  • 12
  • 252
  • 273
  • There is no `Manufacturer` proprety in the ProductSet class that is why I *have* to pass by a join query ... no choice here – Erick Jan 19 '10 at 19:24
  • If so, that is nasty that you have to do that. What is the underlying cause? Is there something special about `struct` that makes this necessary (or is it merely a coincidence that `Guid` and `DateTime` are `struct`?)? – jason Jan 19 '10 at 20:52
  • I don't think it's `struct` that's the issue. But I'm not totally certain what the issue is. I *think* it has to do with the nullability. But like I said, I don't totally understand what's going on. – Craig Stuntz Jan 19 '10 at 21:22
  • 1
    I edited with the query tweaked a bit and it *seems* to work here – Erick Jan 19 '10 at 21:35
  • @Erick and @Jason, I'm wondering if this is related: http://stackoverflow.com/questions/2088231/expression-greaterthan-fails-if-one-operand-is-nullable-type-other-is-non-nullab/2088849#2088849 – Craig Stuntz Jan 20 '10 at 01:07
  • @Craig tried it, (Guid? manufacturerID = new Guid?(new Guid("theguid")); and resulted with a " A severe error occurred on the current command. The results, if any, should be discarded." error... – Erick Jan 20 '10 at 15:22
  • @Craig, more fun to come ! Basically, this source is sent on a ListView, which contains another ListView that calls a method for his datasource. If I null the other method everything is cool but otherwise it just doesn't like it at all. – Erick Jan 20 '10 at 15:56
  • 1
    Not exactly that the answer but I finally rewrited the whole page (was working from another guy's work) ... Basically there was a ListView inside a ListView inside another ListView (go figure...). Now it's working perfecly with only a ListView and a repeater inside the LV. – Erick Jan 21 '10 at 17:12
  • @Craig Stuntz: Yes, that could be if the corresponding table field is declared as, say, `uniqueidentifier NULL`. Yucky. – jason Jan 21 '10 at 17:15
0

Convert to a list first, then call your select statement:

var res = abc.getEmployess().toList().select(x => new keyvaluepair<int, string>(x.EmpID, x.EmpName.tostring)).tolist();