The best way will depend on your dependencies.
Does the POCO / core assembly depend on EF ?
Do you inject Access to DB into your core Library assembly? etc.
I personally use repository/luw pattern, where the various repository objects inherit from a base repository object that is generic. the DAL depends on EF but the POCO classes in core dont.
The repository sub class has a a specific type and DOES the OTHER OBEJCT business checks.
IE business rules that require other entities to be checked , i implement in DAL.
The repository classes belong to the Data Access layer Project and DO have a dependency on EF and have the Context injected. Example below.
Checks specific to the instance I perform on the POCO.
Checks that require DB access I perform via an Interface implemented on a base Class respository class that is inturn overriden as requried. So now calls CheckEntity are triggered when adding or changing an object.
eg
... NOTE some code removed to keep example relevant...
public class RepositoryEntityBase<T> : IRepositoryEntityBase<T>, IRepositoryEF<T> where T : BaseObject
public virtual OperationStatus Add(T entity)
{
var opStatus = new OperationStatus(status: true, operation: OperationType.Add);
try
{
if (OnBeforeAdd != null) // registered listeners of added event?
{
var evtArg = PrepareEventArgs(entity, MasterEventType.Create);
OnBeforeAdd(this, evtArg);
}
opStatus = CheckBeforePersist(entity);
if (opStatus.Status)
{
Initialize(entity);
EntityDbSet.Add(entity);
if (OnAfterAdd != null) // registered listeners of added event?
{
var evtArg = PrepareEventArgs(entity, MasterEventType.Create);
OnAfterAdd(this, evtArg);
}
}
}
catch (Exception ex)
{
opStatus.SetFromException("Error Adding " + typeof(T), ex);
}
return opStatus;
}
//... then in a specific repository class
//... irepositorybase expects Check before persist.
public override OperationStatus CheckBeforePersist(MasterUser entity)
{
// base entity rule check first
var opStatus = new OperationStatus(true, OperationType.Check);
opStatus.ValidationResults = base.CheckEntity(entity);
if (opStatus.ValidationResults.Count > 0)
{
opStatus.Status = false;
opStatus.Message = "Validation Errors";
return opStatus;
}
//now check the local memory
var masterUser = Context.Set<MasterUser>().Local //in context
.Where(mu => mu.Id != entity.Id // not this record
&& mu.UserName == entity.UserName ) // same name
.FirstOrDefault();
if (masterUser != null)
{
opStatus.Status = false;
opStatus.Message = "Duplicate UserName :" + masterUser.UserName + " UserId:"+ masterUser.Id.ToString();
return opStatus;
}
masterUser = Context.Set<MasterUser>().Local //in context
.Where(mu => mu.Id != entity.Id // not this record
&& mu.Email == entity.Email) // same email
.FirstOrDefault();
if (masterUser != null)
{
opStatus.Status = false;
opStatus.Message = "Duplicate Email :" + masterUser.Email + " Username:" + masterUser.UserName;
return opStatus;
}
// now check DB
masterUser = Get(mu => mu.Id != entity.Id //not this record being checked
&& mu.UserName == entity.UserName); // has same username
if (masterUser != null)
{
opStatus.Status = false;
opStatus.Message = "Duplicate UserName :" + masterUser.UserName + " UserId:"+ masterUser.Id.ToString();
return opStatus;
}
masterUser = Get(mu => mu.Id != entity.Id // not this record
&& mu.Email == entity.Email); // but same email
if (masterUser != null)
{
opStatus.Status = false;
opStatus.Message = "Duplicate Email:" + masterUser.Email + " UserName:"+ masterUser.UserName;
return opStatus;
}
return opStatus;
}
}