Entry Framework 4..5: Query Builder - entity-framework

I'm a newby to Entry Framework. I'm working though Julia Lerman's book and I'm stuck with Query Builder method. I get the following compile error:
Error 1 'System.Data.Entity.DbSet<Chapter2ConsoleApp.Contact>' does not
contain a definition for 'Where' and the best extension method overload
'System.Linq.Queryable.Where<TSource>(System.Linq.IQueryable<TSource>,
System.Linq.Expressions.Expression<System.Func<TSource,bool>>)' has some invalid arguments
C:\EF\ProgrammingEntityFramework\Chapter2ConsoleApp\Program.cs 59 32
Chapter2ConsoleApp
There's the code.
using (SampleEntities context = new SampleEntities())
{
var contacts = context.Contacts.Where("it.FirstName = 'Robert'").OrderBy("it.LastName");
foreach (Contact contact in contacts)
{
Console.WriteLine("{0} {1}",
contact.FirstName.Trim(),
contact.LastName);
}
}
Console.Write("Press Enter...");
Console.ReadLine();
}
A Linq to entity with a lambda works OK. When I look at the bad code via IntelliSense I can see that there is a Where method. Finally, I've tried a cast [(IObjectContextAdapter)] on the context but then I couldn't get the Contact method.
Would anyone help me?

Use the following code below (make sure you import System.Data.Entity.Infrastructure namespace)
var contacts = ((IObjectContextAdapter)context).ObjectContext.CreateObjectSet<Contact>()
.Where("it.FirstName = 'Robert'")
.OrderBy("it.LastName");
Thanks,
Kinvi

Related

Entity Framework Z Plus Batch Update

I am using Entity Framework Z Plus Batch Update method. I am unable to proceed due to below issue. Actually Update method works good when i give static values like tagName="amir1". But I need to get the Tagdescription from a web service or from another collection based on the tagId, Update method is not accepting a extension method or any other method to accomplish my requirement.Its saying
"LINQ to Entities does not recognize the method 'System.String GetTagDescription(Int32)' method, and this method cannot be translated into a store expression.".
Hope my requirement is clear now. Please guide me if there is any other approach for my requirement.
Here is my code:
using (var context = new TrialsDBEntities())
{
context.tblTags.Where(x => (tagIdCollection.Contains(x.tagId))).
Update(m => new tblTag { tagDescription = m.tagId.GetTagDescription(), tagName = "amir1" });
}
public static string GetTagDescription(this int i)
{
return "test" + i;
///Replace above line with call to database or web service call
getting some text by giving i as input
}
Disclaimer: I'm the owner of the project Entity Framework Plus
Unfortunately, that's not possible to use BatchUpdate with a value that changes from a row to another.
Disclaimer: I'm the owner of the project Entity Framework Extensions
In this situation, we normally recommend using our paid library that's build for this kind of situation and offer high-performance saving operation.
Example
// Easiest way
context.BulkSaveChanges();
// Fastest way
context.BulkUpdate(tags);
EDIT: Answer comment
If I can't use updated row so why the signature of action is misleading and give me possibility to write like this: e => new Entity { Name = e.Name + "Edited" }
For most providers such as SQL Server, your expression is supported. You give a global expression so we can apply. Your expression doesn't doesn't change from a row to another, it's the same expression.
What is not supported is giving a specific expression from a row to another.
Write your code as follows:
using (var context = new TrialsDBEntities())
{
var tagsToBeUpdated = context.tblTags.Where(x => (tagIdCollection.Contains(x.tagId))).AsNoTracking().ToList();
//Only use this code block if your tagsToBeUpdated list is too large
Parallel.ForEach(tagsToBeUpdated, tagToBeUpdated =>
{
var tagDescription = GetTagDescription(tagToBeUpdated.tagId);
tagToBeUpdated.tagDescription = tagDescription;
context.Entry(tagToBeUpdated).State = EntityState.Modified;
});
//Only use this code block if your tagsToBeUpdated list is not too large
foreach(var tagToBeUpdated in tagsToBeUpdated)
{
var tagDescription = GetTagDescription(tagToBeUpdated.tagId);
tagToBeUpdated.tagDescription = tagDescription;
context.Entry(tagToBeUpdated).State = EntityState.Modified;
}
context.SaveChanges();
}
public static string GetTagDescription(int i)
{
return "test" + i;
///Replace above line with call to database or web service call
//getting some text by giving i as input
}

Laravel 5.4 order by related table after using `with` statement

This is my simple structure:
public class Post{
public function user(){
return $this->belongsTo(User::class);
}
}
This is how I query (the query has pagination):
$query = Post::query();
$query->with('user');
I want to sort by user.name.
Now, I know that I can go $query->with('user',function(){...order by here});
But I need a detached method that I can run later in the stack.
$query->user->orderBy('name');
$query->user()->orderBy('name');
This https://stackoverflow.com/a/38741988/936651 says that it is possible, but I get the error: Undefined property/method: Illuminate\Database\Eloquent\Builder::$user
Is there any way to sort by related table after using with statement?
Thanks
Your code doesn't work because when you do $query = Post::query(); it will return an instance of the Query Builder, so when you after do $query->user() it gives you an error because the Query Builder does not have the method user(), that method exists in your Post model.
I won't provide any code since you've mentioned you already know how to do the with() way..

MVC5 EF6 with migrations - seeding a membership user

I am setting up my seed methods in my migration's configuration class.
I have added a reference to the following name spaces
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
and wrote up the following method that gets called from the Seed method
private void SeedMembership(MyDbContext context)
{
var user = new ApplicationUser() { UserName = "demo"};
UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
var result = UserManager.Create(user,"demo");
}
The idea was to have this aoto create a user with username=demo and password=demo
but I cant compile getting the following error:
using the generic type 'Microsoft.AspNet.Identity.UserManager<TUser>' requires 1 type argument
I am a bit stuck as to why.
Thanks!
You seem to have a typo:
var result = UserManager.Create(user,"demo");
You should use userManager, note the lower-case u.

EF 4.0 Dynamic Proxies POCO Object Does not match target type

I am using EF 4.0 and POCO's. I stumbled across this error while inserting to records into the data base.
Property accessor 'QualityReasonID' on object 'BI.Entities.QualityReason' threw the following exception:'Object does not match target type.'
There errors occur on the Databind to a GridView after saving a new record to the database. I identified what is happening but I am not sure WHY it is occurring or If I am using EF/POCO's incorrectly. Any insight would be appreciated.
The exception is occuring because the object types in the IEnumerable are not the same.
The orginal entrys in the table are of type System.Data.Entity.DynamicProxies.QualityReason_E483AD567288B459706092F1825F53B1F93C65C5329F8095DD1D848B5D039F04}
While the new one is BI.Entities.QuailtyReason.
Here is how I insert the new object.
public void createQualityReason(QualityReason qReasons)
{
dbcontext.QualityReasons.AddObject(qReasons);
dbcontext.SaveChanges();
}
I resolved the error by changing the fetch code from:
public IEnumerable<QualityReason> fetchQualityReasons()
{
IEnumerable<QualityReason> queryReasons = dbcontext.QualityReasons.AsEnumerable();
return queryReasons;
}
to
public IEnumerable<QualityReason> fetchQualityReasons()
{
IEnumerable<QualityReason> queryReasons = from data in dbcontext.QualityReasons.AsEnumerable()
select new QualityReason
{
QualityReasonID = data.QualityReasonID,
QualityReasonName = data.QualityReasonName
};
return queryReasons;
}
So to get around the error I have to select into the POCO class explicitly each time. This feels like I am going something wrong. Any thoughts?
The error is caused because GridView does not handle polymorphic datasources when using boundfields. So you have two options
Use TemplateFields instead which can handle polymorphic datasources, this may changing some of your front end code and GridView events.
Use Linq to create a non-polymorphic databsource that the boundfields can handle
So instead of using something like ti
gvGroups.DataSource = ProductHelper.Get()
gvGroups.DataBind();
var query = from p in ProductHelper.Get()
select new {p.ProductId, p.ProductName, p.ProductDesc, p.ProductLink};
gvGroups.DataSource = query;
gvGroups.DataBind();
I don't know if the problem has been solved yet, but I've had the same problem with my (POCO) "Scenario" class.
The problem disappeared when using a context.CreateObject<Scenario> to create the (POCO) object i.s.o. a .... = new Scenario().
Faced the same issue today and used Value Injecter to solve it. It's as simple as:
var dynamicProxyMember = _repository.FindOne<Member>(m=>m.Id = 1);
var member = new Member().InjectFrom(dynamicProxyMember) as Member;
That's it :)

How to get rid off "An entity object cannot be referenced by multiple instances of IEntityChangeTracker"?

I have a model in Ado.Net EF.
I have a one to many relation and when I want to Add the entities I get the error
"An entity object cannot be referenceed by multiple instances of IEntityChangeTracker"
Any clue?
Something similar to
Template template = new Template();
...
...
while (from < to)
{
Course course = new Course();
.....
template.Course.Add(course);
.....
}
courseEntities.AddToTemplate(template); // Problem line
courseEntities.SaveChanges();
I was getting this message until i started to store the data context in the HttpContext.Items Property. This means you can use the same data context for the current web request. That way you don't end up with 2 data contexts referencing the same entities.
Here is a good post on DataContext Life Management.
I hope it helps.
Dave
"template", or something that it references, has already been added to courseEntities or another context. I don't see anything in the code you show it would do that, but it is certainly happening. Perhaps it's happening in some of the code that you've trimmed. Look at the EntityState property of "template" in the debugger, and look at the EntityState of the properties of "template" as well. This should help you find out which entity instance is already in a context.
I already realize the problem. I have another relation and I get the other entity from another context.
Let me relate my experience with this nasty error and point out the terrain chasing it will take you over leading to a tremendously simple solution.
CompanyGroup is pretty simple. It has a name and it has a Company object.
I started with this:
1 public static void Add(CompanyGroup item)
2 {
3 try
4 {
5 using (Entities scope = new Entities())
6 {
7 scope.AddToCompanyGroup(item);
8 scope.SaveChanges();
9 }
10 }
11 catch (Exception ex)
12 {
13 LogException(ex, item);
14 throw;
15 }
16 }
And got this error:
{"An entity object cannot be
referenced by multiple instances of
IEntityChangeTracker."}
So, I added this between lines 6 and 7:
(IEntityWithChangeTracker)item).SetChangeTracker(null);
That rewarded me with:
{"The object cannot be added to the
ObjectStateManager because it already
has an EntityKey. Use
ObjectContext.Attach to attach an
object that has an existing key."}
So I changed
scope.AddToCompanyGroup(item);
to
scope.Attach(item);
Now it complained about:
{"An object with a temporary EntityKey
value cannot be attached to an object
context."}
(beginning to sound like some of the girls I dated in my youth -- never content -- but I digress)
So I made the entity key null (didn't work) and used the method to create new (didn't work, either)
Along the way, I got this error, too:
{"The source query for this
EntityCollection or EntityReference
cannot be returned when the related
object is in either an added state or
a detached state and was not
originally retrieved using the
NoTracking merge option."}
The Solution?
Replace the core, lines 7 and 8, with:
CompanyGroup newcg = new CompanyGroup();
newcg.GroupName = item.GroupName;
newcg.Company = scope.Company.Where(c => c.CompanyID == item.Company.CompanyID).First();
scope.AddToCompanyGroup(newcg);
scope.SaveChanges();
Essentially, I took the data passed via 'item', and moved it to newly created object of the same type that introduces the same
scope as the one used in the Add.
I hope this is the simplest and correct solution. You need one db context per httprequest.
EF4 Code First template Global.asax.cs
http://gist.github.com/574505
void MvcApplication_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Items[SessionKey] = new Db();
}
void MvcApplication_EndRequest(object sender, EventArgs e)
{
var disposable = HttpContext.Current.Items[SessionKey] as IDisposable;
if (disposable != null)
disposable.Dispose();
}
Please initialize your Entities only one time.
Like as
If You more than one time initialize your Entities.
You will get the error:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
ex:
public class Test
{
private Entities db=new Entities();
public static void Add(CompanyGroup item)
{
try
{
db.CompanyGroup.Add(item);
db.SaveChanges();
}
catch (Exception ex)
{
}
}
}
This problem I was solved by removing from the object that I update, extra relationships with other entities (Virtual). Left only their ID.
This is wrong code
dataFileEntity.IterParameterValue = parameterValueEntity.ParameterValue;
dataFileEntity.IterParameterValueId = parameterValueEntity.ParameterValue.Id;
dataFileEntity.ResultParameter = parameterValueEntity.ResultParameter;
dataFileEntity.ResultParameterId = parameterValueEntity.ResultParameter.Id;
dataFileEntity.RawDataResult = result.Value;
This is right
dataFileEntity.IterParameterValueId = parameterValueEntity.ParameterValue.Id;
dataFileEntity.ResultParameterId = parameterValueEntity.ResultParameter.Id;
dataFileEntity.RawDataResult = result.Value;
RequestTestRawDataFileRepository.AddOrUpdate(dataFileEntity);
Я эту проблему решила, убрав из объекта, который я апдейтила лишние связи с другими сущностями (Virtual). Оставила только их id.