cshtml runtime error: Only parameterless constructors and initializers are supported in LINQ to Entities - asp.net-mvc

Want to use objects of a public class in cshtml, but got a runtime error: Only parameterless constructors and initializers are supported in LINQ to Entities. What is wrong with the following statement? Thanks for any help!
#foreach (var obj in ViewData["IncompleteList"] as IEnumerable<Games.TeamAction>)
The controller fills the ViewBag, like
IEnumerable<TeamAction> incomplete = dbIncAct.IncompleteActivity.Where(a => a.activityID == id)
.Select(s => new TeamAction(s.teamID, s.name, id, s.type));
ViewBag.IncompleteList = incomplete;
The class TeamAction (part of the namespace Games) is quite simple:
public class TeamAction
{
public TeamAction()
{
}
....
public int teamID {get; set;}
public string teamName { get; set; }
public int activityID { get; set; }
public int actionType { get; set; }
}

The answer is in the error message, once you figure out how to interpret it.
You are creating an IEnumerable via LINQ to Entities (the Entity Framework LINQ provider) like so:
IEnumerable<TeamAction> incomplete = dbIncAct.IncompleteActivity
.Where(a => a.activityID == id)
.Select(s => new TeamAction(s.teamID, s.name, id, s.type));
Note that your Select call includes a lambda expression that calls the TeamAction constructor that takes 4 parameters. As soon as you ask for the first element in the IEnumerable, LINQ tries to execute your query. At that point, it parses your lambda expression and tries to translate it into an Entity Framework query that it can run. But, as the exception message says:
Only parameterless constructors and initializers are supported
You cannot include the parameterized constructor in your LINQ query because LINQ to Entities doesn't know how to execute it. To fix the problem you have a few options.
Option One: IQueryable -> IEnumerable
The easiest way around this is to make sure the EF LINQ provider never sees the offending lambda, by forcing your IQueryable into an IEnumerable before it gets there. dbIncAct.ImcompleteActivity is probably a DbSet<>, and DbSet<>.Where returns an IQueryable that is still dependent on LINQ 2 Entities. To break that dependency, you can do:
IEnumerable<TeamAction> incomplete = dbIncAct.IncompleteActivity
.Where(a => a.activityID == id)
.AsEnumerable()
.Select(s => new TeamAction(s.teamID, s.name, id, s.type));
That will force your EF query to run up through the Where part and return an enumerable collection of IncompleteActivity entities. That thing (some internally-defined List-like object) is then used to call Select, completely apart from EF.
The downside here is that you're forcing the EF query, which probably hits a database, to happen immediately. If you don't want that, your only choice is to eliminate the parameterized constructor, using one of the other two options.
Option Two: Object Initializers
Depending on what that constructor did, you may or may not be able to easily fix it. If your constructor is just there to set properties on your newly created object, you're in luck. C# introduced the new object initializer syntax to go along with LINQ and lambdas for precisely this reason:
IEnumerable<TeamAction> incomplete = dbIncAct.IncompleteActivity
.Where(a => a.activityID == id)
.Select(s => new TeamAction
{
TeamId = s.teamID,
Name = s.name,
Id = id,
Type = s.type
});
Option Three: Refactor
If your constructor does any actual work, then you'll need to do some refactoring. Try to move as much logic into your default TeamAction() constructor as you can. You can also put some of the logic into the property setters, though you should try to minimize that as much as you can.
If your object really does require some complex initialization, the typical pattern to have an initialization method that gets called early in the life cycle, e.g:
var x = new X { ... };
x.InitializeMe();
You could do this, for example, inside your #for loop, or as a separate step immediately after you create your query.

Change it to object initialization instead:
IEnumerable<TeamAction> incomplete = dbIncAct.IncompleteActivity.Where(a => a.activityID == id)
.Select(s => new TeamAction { teamID = s.teamID, teamName = s.name, activityID = s.id, actionType = s.type });

Related

How can I use IEnumerable.Where().Count() in LINQ query?

In Enitity Framework I'd like to use a linq query in the where clause of another linq query.
public class A {
}
public class B {
public A A { get; set; }
}
public class AB {
public A A { get; set; }
public B B { get; set; }
}
IEnumerable<MassiveObject> filteredData = ... // MassiveObject contains A and some more attributes
var query = from b in db.Bs
.Include("A")
where filteredData.Where(x => x.A.equals(b.A)).Count() > 0 // filteredAs contains an object that contains the same A as the b's A
select new AB {
A = filteredData.Where(a => a.equals(b.A)),
B = b
};
It looks like LINQ doesn't support that. "Unable to create a constant value of type 'MassiveObject'. Only primitive types or enumeration types are supported in this context." Neither the first nor the second use of the nested linq.
Is there another way to this without looping through the query's results after the query was executed?
filteredData is a collection that exists inside the memory of your process. On the other hand, the EF query is translated into SQL that runs on the SQL server.
The SQL server cannot know what data exists in the memory of your process, and even if it could see that memory SQL still has no concept of object instances or iteration. So what you are trying to do is fundamentally impossible.
Linq does not support using an enumeration of an object in a SQL construct because there is no way to make that a SQL stement to start with.
Pull the b's and then filter in that enumeration.
You can't mix in-memory and SQL LINQ queries like this. Instead you need to pull the SQL data into memory before doing the join.
Try something like this instead:
var query =
from b in db.Bs.Include("A").ToArray()
join a in filteredData.Select(x => x.A) on b.A equals a into gas
where gas.Any() // or use gas.Count() > 0
select new AB
{
A = gas.First(),
B = b,
};
Note the .ToArray() call that brings the SQL data into memory.
It isn't very clear what you are trying to achieve, however, previous queries can be used in the current query in various ways e.g.
query2 = source.Where(s => query1.Contains(s));
or using LINQ joins.
In your case itlooks like youare trying to reuse a filter,not a query.
You can achieve this using an extension method from IQueryable<T> to IQueryable<T> or by using expressions.
e.g.
static class MyExtensions
{
public static void IQueryable<T> FilterResults(this IQueryable<T> query)
{
return query.Where(i => i....);
}
}
and then use like so:
query2 = query.FilterResults().Where(...);
For details on the alternative of using Expression Trees see this MSDN article.

How to update eagerly loaded entity with relations

I am using EF4 with ASP.Net MVC, and I wonder how am I to update entity which was loaded eagerly?
When I load the entity as follows:
static readonly Func<Entities, Guid, IQueryable<Call>> CallByGuid =
CompiledQuery.Compile<Entities, Guid, IQueryable<Call>>(
(db, callGuid) =>
db.Calls
.Where(c => !c.Removed && c.CallGUID.Equals(callGuid)));
public Call GetCall(Guid guid)
{
return CallByGuid.Invoke(_db, guid).Single();
}
and pass the entity to the View, edit it there and return back to Controller and save it as follows:
public Call UpdateCall(Call call)
{
_db.ObjectStateManager.ChangeObjectState(call, EntityState.Modified);
_db.Call_VoiceCall.ApplyCurrentValues(call);
_db.SaveChanges();
Call dbCall = FindCall(call.CallGUID);
return dbCall;
}
everything works fine, though quite slow. When I load the entity as follows:
static readonly Func<Entities, Guid, IQueryable<Call>> CallByGuid =
CompiledQuery.Compile<Entities, Guid, IQueryable<Call>>(
(db, callGuid) =>
db.Calls
.Include("Call_VoiceCall")
.Include("Call_Rating")
.Include("Memos")
.Include("Company")
.Include("PhoneService")
.Where(c => !c.Removed && c.CallGUID.Equals(callGuid)));
public Call GetCall(Guid guid)
{
return CallByGuid.Invoke(_db, guid).Single();
}
the list of entities loads very fast, but I cannot update an entity: what I get is
"Violation of PRIMARY KEY constraint 'PK_Call_5599FCED3AE4474F'.
Cannot insert duplicate key in object 'dbo.Call'. The duplicate key
value is (6d078f37-29e6-4e56-9853-d793994ce163). The statement has
been terminated."
or something like this.
Now, since it is almost impossible to google questions on the similar topic, I am doing something seriously wrong. What is it?

How to MapFrom a collection? Auto mapper

I have a linq to sql object that has some references to some other tables
I am trying to map it to a vm but nothing ever gets captures.
Mapper.CreateMap<A, G>();
// A is the linq to sql object
A.MyList // this is a collection that I am trying to get the value out of A.MyList.Id
// G is my View Model
public class G
{
public string AMyListId {get; set;}
}
vm = Mapper.Map<List<A>, List<G>>(aListOfAFromDb);
This always comes back from null. I thought I would have to do it manually so I tried
Mapper.CreateMap<A, G>().ForMember(dest => dest.AMyList , opt => opt.MapFrom(src =>????));
but since I am getting it from a list it won't give any of the properties to choose from.
Edit
I realized that I should not have a list of "MyList" it should be a one to one. I still am having problems trying to do what I want to do.
I have this
Mapper.CreateMap();
A.Vip.UserId // again my linq object is A
// G is my View Model
public class G
{
public string IsVip {get; set;}
}
vm = Mapper.Map<List<A>, List<G>>(aListOfAFromDb);
Mapper.CreateMap<A, G>().ForMember(dest => dest.IsVip, opt => opt.AddFormatter<VipFormatter>());
public class VipFormatter : IValueFormatter
{
public string FormatValue(ResolutionContext context)
{
bool value = (bool)context.SourceValue;
if (value)
{
return "Yes";
}
return "No";
}
}
yet nothing every gets bound. I am not sure why. Do I have to do change my property to "AVipUserId"? Or somehow tell it to map?
From what I can see in your code, and in addition to my comment above, you don't need AutoMapper for this one:
List<A> dbItems;
IEnumerable<G> results = dbItems.Select(x => x.MyList.MyListID);
In fact, you can't map A to G, because you're going to create multiple "G" objects for each "A" object.
Let me know if I misunderstood the question here.
UPDATE:
I would change "G" to use a boolean property and then do the following:
Mapper.CreateMap<A, G>().ForMember(dest => dest.IsVip, opt => opt.MapFrom(src => src.Vip == null));
Or, whatever logic you use to determine if it is a VIP or not.
How about:
List<G> items = // whatever
var result = items.Select(g => Mapper.Map<G, A>(g));

compiled query only scalar parameters are allowed !

I am using POCO objects in EF 4 without any T4 template generation.
I have a DataContext class that encapsulates all ObjectSets, something like this
public sealed class DataContext :IDisposable
{
public IObjectSet GetObjectSet() where T : MyBase
{
object objectSet = null;
this.objectSets.TryGetValue(typeof(T), out objectSet);
if (objectSet == null)
{
objectSet = this.context.CreateObjectSet();
this.objectSets.Add(typeof(T), objectSet);
}
return (IObjectSet)objectSet;
}
public ObjectContext ObjectContext
{
get
{
return this.context;
}
}
}
When i write the following compiled query and try to pass in this class as one of the parameters, it gives me a runtime error saying only scalar parameters are allowed
static readonly Func<ObjectContext , DataContext, string, int?> getOperationByOrchestrationName
= CompiledQuery.Compile(
(ObjectContext ctx, DataContext container, string name) =>
(from or in container.GetObjectSet<MyOrClass>()
join op in container.GetObjectSet<MyOpClass>()
on or.Id equals op.Id
where op.Name == name
select op.Id).FirstOrDefault()
);
If i modify the query like this it works, but i deeply suspect its being compiled every time, since i am not seeing the performance boost i would see from a compiled query, can someone point out whats going on ?
static readonly Func, IObjectSet, string, IQueryable>
getOperationByOrchestrationName
= CompiledQuery.Compile(
(ObjectContext ctx, IObjectSet ors, IObjectSet ops,string operationName) =>
from or in ors
join op in ops
on or.Id equals op.Id
where op.Name == name
select op.Id
);
for anyone interested, if you return IQueryable from compiled query and call any of the methods that can change the query ( singleordefault, or firstordefault etc), you would not get benefit of a compiled query.

Iterating over an unknown IQueryable's properties?

Forgive me if this has been asked before; I couldn't find anything close after a few searches:
I'm trying to write an ActionFilter in MVC that will "intercept" an IQueryable and nullify all the parent-child relationships at runtime. I'm doing this because Linq does not serialize objects properly if they have parent-child relationships (it throws a circular reference error because the parent refers to the child, which refers back to the parent and so on), and I need the object serialized to Json for an Ajax call. I have tried marking the child relationship in the DBML file with a privacy status of internal, and while this fixes the serialization problem, it also hides the child members from the view engine when the page renders, causing another error to be thrown. So, by fixing one problem, I cause another.
The only thing that fixes both problems is to manually set the child members to null just before returning the serialization, but I'm trying to avoid doing that because it's cumbersome, not reusable, etc. I'd rather use an ActionFilter to inspect the IQueryable that is being serialized and nullify any members with a Type of EntitySet (how Foreign Keys/Associations are represented). However, I don't have much experience with Reflection and can't find any examples that illustrate how to do something like this. So... is this possible with Reflection? Is there a better way to accomplish the same thing? I'll post the relevant code tomorrow when I'm back at my work computer.
Thanks,
Daniel
As promised, the code:
[GridAction]
public ActionResult _GetGrid()
{
IQueryable<Form> result = formRepository.GetAll();
foreach (Form f in result)
{
f.LineItems = null;
f.Notes = null;
}
return View(new GridModel<Form> { Data = result });
}
An added wrinkle is that I'm using the new Telerik MVC Extensions, so I'm not actually serializing the Json myself -- I'm just returning the IQueryable in an IGridModel, and the action filter [GridAction] does the rest.
So, just in case anyone's curious, here's how I finally solved this problem: I modified Damien Guard's T4 template to include the attribute [ScriptIgnore] above entities of type Association. This lets the JSON serializer know to not bother serializing these, thus preventing the circular reference problem I was getting. The generated code ends up looking like this:
private EntitySet<LineItem> _LineItems;
[ScriptIgnore]
[Association(Name=#"Form_LineItem", Storage=#"_LineItems", ThisKey=#"Id", OtherKey=#"FormId")]
public EntitySet<LineItem> LineItems
{
get {
return _LineItems;
}
set {
_LineItems.Assign(value);
}
}
This fixes the serialization problem I was having without disabling the use of child tables through LINQ. The grid action on the controller ends up looking like this:
[GridAction]
public ActionResult _GetGrid()
{
return View(new GridModel<Form> { Data = formRepository.GetAll() });
}
There are two options, one is to ignore those properties during serialization using [XmlIgnore]. The other one is to nullify the properties using reflection.
Ignore in serialization, simple usage sample that shows how to use default value in serialization:
[Serializable]
public class MyClass
{
[XmlIgnore]
public int IgnoredVal { get; set; }
public int Val { get; set; }
}
public void UsageSample()
{
var xmlSerializer = new XmlSerializer(typeof(MyClass));
var memoryStream = new MemoryStream();
var toSerialize = new MyClass { IgnoredVal = 1, Val = 2 };
xmlSerializer.Serialize(memoryStream, toSerialize);
memoryStream.Position = 0;
var deserialize = (MyClass)xmlSerializer.Deserialize(memoryStream);
Assert.AreEqual(0, deserialize.IgnoredVal);
Assert.AreEqual(2, deserialize.Val);
}
Nullify with reflection, code sample:
public void NullifyEntitySetProperties(object obj)
{
var entitySetProperties = obj.GetType().GetProperties()
.Where(property => property.PropertyType == typeof(EntitySet));
foreach (var property in entitySetProperties)
{
property.SetValue(obj, null, null);
}
}
In my opinion, if the first option can be done used in your code it's better. This option is more direct and economic.

Resources