In the entity designer I set the conditional mapping on an entity where it filters all customers by an 'isactive' field.
That works great no problem with that, but the problem comes in my linq.
What happens when I need to set a customer to 'IsActive=false'. The property isn't mapped to my entity because the condition is mapped, but in Linq I can't find a way to change that.
using (var db = new CustDbConn())
{
Customer customer= db.Customers.Single(p => p.Id == idFromEmail);
customer.IsActive = false; //<----NOT FOUND, can not resolve 'isActive'
}
There has to be a way to access and change the conditions in LINQ, can someone shed some light on this? I thought about bypassing the model and just updating it using SqlCommand, but I shouldn't have to go through all that.
You can't change model (that's you're trying to do) using LINQ query.
The only way to manipulate IsActive property is to bring it into Customer model, and throw away conditional mapping.
UPD.
You're misunderstanding the main purpose of conditional mapping - inheritance.
Note, that using EF you don't work with database tables, you work with entity types. All you have, is a model. If any table field is missing from model, than yes, you can't access it via model. With reference to your question, yes, you can't change patients activity status, because there's no activity status in the model.
And yes, if you plan to use some sort of deletion/activity marker (like IsActive in you sample), you have to include it in your queries, otherwise you'll get inactive/deleted items in results. Of course, you can make helper/repository/wrapper/etc to automate it:
interface IEntity
{
int Id { get; }
bool IsActive { get; set; }
}
interface IRepository<T>
where T : IEntity
{
IQueryable<T> Get(bool includeInactiveEntities = false);
}
Related
I'm new to nhibernate and I couldn't figure this one out.
I have an entity similiar to below class;
public class MotherCollection
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual ISet<Class1> Collection1 { get; set; }
public virtual ISet<Class2> Collection2 { get; set; }
public virtual ISet<Class3> Collection3 { get; set; }
public virtual ISet<Class4> Collection4 { get; set; }
}
There are numerous one to many relationships to other entities.
I configure this relation with below mappings;
HasMany(d => d.Collection1).KeyColumn("McId");
HasMany(d => d.Collection2).KeyColumn("McId");
HasMany(d => d.Collection3).KeyColumn("McId");
HasMany(d => d.Collection4).KeyColumn("McId");
Child classes are configured similiary;
References(c1=>c1.MotherCollection).Column("McId");
and so on.
When I query this entity from db, fetching all relationships, I get a huge query similar to this one :
SELECT * FROM MotherCollection mc
JOIN c1 on mc.Id=c1.mcId
JOIN c2 on mc.Id=c2.mcId
JOIN c3 on mc.Id=c3.mcId
JOIN c4 on mc.Id=c4.mcId
this query causes alot of duplicate rows and takes alot of time to execute.
I want nhibernate to somehow seperate this query to individual SELECT queries, like below
SELECT * FROM MotherCollection Where Id = #Id
SELECT * FROM c1 Where mcId = #Id
and such. A bit similar to how it happens when the collection is lazy loaded.
I managed to achive this behaviour by setting my desired collections as lazy, and accessing their First() property just before it exits my datalayer. However, I'm guessing there must be a more elegant way of doing this in Nhibernate.
I've tried queries similar to this:
var data = session.QueryOver<DataSet>().Fetch(d=>d.Collection1).Eager.Fetch(d=>d.Collection2).Eager....
Thank you.
You should issue 4 separate queries, each one fetching one collection.
And you should use session.Query. QueryOver is an older way of doing it. To use it add using NHibernate.Linq. I usually use the following extension method to prefetch collections:
static public void Prefetch<T>(this IQueryable<T> query)
{
// ReSharper disable once ReturnValueOfPureMethodIsNotUsed
query.AsEnumerable().FirstOrDefault();
}
And then use:
var data = session.Query<DataSet>().Fetch(d=>d.Collection1).ToList();
session.Query<DataSet>().Fetch(d=>d.Collection2).Prefetch();
session.Query<DataSet>().Fetch(d=>d.Collection3).Prefetch();
session.Query<DataSet>().Fetch(d=>d.Collection4).Prefetch();
Make sure to run the 4 queries before accessing the collections. That way when you access them they will all be initialized already. If you use regular lazy loading you will be initializing one collection for one object at a time.
This is called lazy/eager loading. You have two choices to select from:
1. Lazy load with multiple queries:
This will generate multiple queries. While lazy loading, NHibernate first generates the query to get all MotherCollection data and only IDs (without data) from any dependent tables. Then it generates new query with WHERE clause for Primary Key on dependent table. So, this leads to famous N+1 issue.
With this, referenced collections will NOT be filled by default. Those will get filled up when you first access them while ISession is still valid. This is similar to calling First() as you mentioned in your question.
Look at your HasMany configuration; you have not mentioned LazyLoad but it is default. So, with your current mapping, this is what is happening.
This is recommended by NHibernate.
2. Eager load with single complex query:
If you want to avoid multiple queries and retrieve all the data in one go, try something like following:
HasMany(d => d.Collection1).KeyColumn("McId").Inverse().Not.LazyLoad().Fetch.Join();
With this, referenced collections will be filled up (if data present in database) automatically.
Please note that this is against the NHibernate recommendation. Refer this link.
Instead, we keep the default behavior, and override it for a
particular transaction, using left join fetch in HQL. This tells
NHibernate to fetch the association eagerly in the first select, using
an outer join. In the ICriteria query API, you would use
SetFetchMode(FetchMode.Join).
If you ever feel like you wish you could change the fetching strategy
used by Get() or Load(), simply use a ICriteria query, for
example:
User user = (User) session.CreateCriteria<User>()
.SetFetchMode("Permissions", FetchMode.Join)
.Add( Expression.Eq("Id", userId) )
.UniqueResult();
A completely different way to avoid problems with N+1 selects is to
use the second-level cache.
Duplicate rows and Performance
This is actually a different problem. There are multiple ways to handle this; but it will need additional inputs from you. Before that, you should choose one option from above two. Thus this deserves a new question to be asked.
Refer this answer: https://stackoverflow.com/a/30748639/5779732
I am trying to update an entity in the database using EF4.0 so I'm doing this:
_dbctx.AddObject("MyEntities", EntityWithUpdates);
_dbctx.ObjectStateManager.ChangeObjectState(EntityWithUpdates, EntityState.Modified);
_dbctx.SaveChanges();
MyEntities has a property named StateID. Using debug I can see the correct value in the StateID property of 217 when it is added to the context, but the value is somehow changed to 0 when ObjectStateManager.ChangeObjectState completes.
Has anyone seen this before?
This is the only property on the entity having trouble. Should the StateID property name be avoided or is there a work around?
My entity looks like this:
public class MyEntity
{
public int ID { get; set; }
public int StateID { get; set; }
}
If I get the entity from the database first. Then apply current values everything works wonderfully like this:
MyEntity entity = _dbctx.MyEntities.Where(i => i.ID == id).FirstOrDefault();
_dbctx.ApplyCurrentValues("MyEntities", EntityWithUpdates);
_dbctx.SaveChanges();
This does appear to be an object graph problem, but I still prefer being able to attach the entity and save to avoid the db call.
I looked at several other entities in the application and believe eran otzap is correct. The entire object graph is being saved with includes the State. Because the state isn't loaded EF wants to create it even though it has a valid ID. So it seems the only safe way to apply changes to this entity is to first get it from then db, apply, and then save changes. Bummer.
For anyone else who might see this. eran otzap suggests applying a value for StateID. He said this "might" work. In my situation it did not. I had to get the entity first before EF would recognize the StateID.
I have added a property to a partial class of a model. This property will retrieve a model from database according to property value.
Example:
class movie
{
int language;
}
partial movie
{
public Language SpokenLanguage
{
get
{
var currLang = db.Languages.Where(ml => ml.ID == this.language).FirstOrDefault();
return currLang;
}
}
}
Is this approach will affect application performance when I retrieve a list of movies?
If so what is the equivalent and better performance?
EF will ignore the SpokenLanguage property in your case.
However, you can make EF retrieve the SpokenLanguage using a INNER JOIN by adding a relation in your model between the two tables.
You can also make it retrieve the SpokenLanguage lazily (on demand)-it will actually make a better version on what you wrote, but if you are sure you want to print the language label in your view, it's better to retrieve it using a INNER JOIN.
I have an entity that I need to return only records where a given field value is greater than zero. I have seen examples of conditional mapping in the edmx and that seems like what I am in need of. However, my project is in EF 4.1 code first.
Is there not a way to do this using the code first approach?
I dont think there is an inbuilt method for achieving this, you can however expose a property in your DbContext in which you apply filtering, initially this will be readonly but i dont see a reason why you shouldnt be able to create your own DbSet implementation reflecting back to another DbSet (ProxyDbSet)
Readonly example:
class MyDbContext : DbContext
{
public IDbSet<User> Users { get; set; }
public IQueryable<User> Admins
{
get
{
return from user in users
where user.Role == "admin"
select user;
}
}
}
Basically, I need to set a property to the results of a query that uses data from the parent object.
With the domain model below, I need to set the C property of EntityB using data from both EntityA and EntityB.
Also, I need to set the A property of EntityB to be the actual instance of EntityA that is its parent.
Query:
Set EntityB.C = (select * from EntityC where SomeProperty = EntityB.SomeProperty and AnotherProperty = EntityB.A.AnotherProperty);
SomeProperty and AnotherProperty are not just keys.
class EntityA
{
public IList<EntityB> B
{
get;
set;
}
}
class EntityB
{
public EntityA A
{
get;
set;
}
public EntityC C
{
get;
set;
}
}
class EntityC
{
...
}
I need a way to execute code (to run the query and assign to property) for each entity returned. I came close using the onload method of an interceptor, but I am looking for another way. Perhaps using a Result Transformer or a Projection?
First of all, if you're using NHibernate properly, the properties and associations should be automatically done for you by the framework. If they're not, then you don't have it set up correctly...
As for doing a query in a property... this is usually not recommended (abstract it into a utility class, or at the very least a function call), but I do remember seeing some way on here how to do it.
There are actually two questions.
Question 1: How to have a property that is loaded by some query?
Ask your self if it really needs to be in the entity. Consider to have a DTO (data transfer object) that holds data from different entities and queries instead.
If you're sure that you need this property in the entity, take a look at formulas for single ended properties and filters for collections.
I can't provide more detailed information, because your question is highly general, and it depends on the actual problem. But you should find a solution by starting with the given links.
Question 2: How can I have a property pointing to the parent?
Very easy: By just implementing the property and map the collection of children (B) "inverse=true". Implement your entities the way that they consistently point to the correct parent.
Why is NH not doing this for you? Because NH's responsibility is only to persist your entities to the database. NH does not make any changes on the data by its own. This is responsibility of your business logic.
Note: your application should also be able to run without NH, eg in a unit test. So relations should be managed in your code.