我启动了一个ASP.NET Web项目应用程序来学习如何使用EF4。在我的项目中,我定义了3个层(dal=>实体框架4,bll=>业务逻辑层,ui)。
使用EF4的模板功能生成的BLL和DAL共享POCO。
例如,我的“用户”poco类如下所示:
public partial class User
{
#region Primitive Properties
public virtual System.Guid Id
{
get;
set;
}
public virtual string Name
{
get;
set;
}
public virtual string Password
{
get;
set;
}
public virtual string Email
{
get;
set;
}
public virtual bool MarkedForDeletion
{
get;
set;
}
#endregion
#region Navigation Properties
public virtual Role Role
{
get { return _role; }
set
{
if (!ReferenceEquals(_role, value))
{
var previousValue = _role;
_role = value;
FixupRole(previousValue);
}
}
}
private Role _role;
public virtual ICollection<Article> Articles
{
get
{
if (_articles == null)
{
var newCollection = new FixupCollection<Article>();
newCollection.CollectionChanged += FixupArticles;
_articles = newCollection;
}
return _articles;
}
set
{
if (!ReferenceEquals(_articles, value))
{
var previousValue = _articles as FixupCollection<Article>;
if (previousValue != null)
{
previousValue.CollectionChanged -= FixupArticles;
}
_articles = value;
var newValue = value as FixupCollection<Article>;
if (newValue != null)
{
newValue.CollectionChanged += FixupArticles;
}
}
}
}
private ICollection<Article> _articles;
public virtual Status Status
{
get { return _status; }
set
{
if (!ReferenceEquals(_status, value))
{
var previousValue = _status;
_status = value;
FixupStatus(previousValue);
}
}
}
private Status _status;
#endregion
#region Association Fixup
private void FixupRole(Role previousValue)
{
if (previousValue != null && previousValue.Users.Contains(this))
{
previousValue.Users.Remove(this);
}
if (Role != null)
{
if (!Role.Users.Contains(this))
{
Role.Users.Add(this);
}
}
}
private void FixupStatus(Status previousValue)
{
if (previousValue != null && previousValue.Users.Contains(this))
{
previousValue.Users.Remove(this);
}
if (Status != null)
{
if (!Status.Users.Contains(this))
{
Status.Users.Add(this);
}
}
}
private void FixupArticles(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (Article item in e.NewItems)
{
item.Author = this;
}
}
if (e.OldItems != null)
{
foreach (Article item in e.OldItems)
{
if (ReferenceEquals(item.Author, this))
{
item.Author = null;
}
}
}
}
#endregion
}
因为所有属性都用虚拟EF4标记,所以应该创建一个代理类来访问POCO的所有数据。另外,我还为DB上下文启用了延迟加载。
当我想显示用户的详细信息时,我有一个放松场景:
-
ui=>从bll(usersmanager)实例化一个类,并调用返回用户的getuserbyemail(string email)方法。
-
bll=>在usersmanager类型的getuserbyemail(string email)方法中,我从dal(usersdatamanager)实例化一个类,并调用返回用户的getuserbyemail from dal(string email)方法。
-
dal=>在getuserbyemailfromdal(字符串email)中,我实例化了一个上下文,为用户查询并返回它。
问题是,因为只有DAL知道上下文,并且在它退出函数后才进行处理,所以POCOS导航关系为空,并且我对它们的任何属性都没有访问权。
如果我执行myuser.role.name,就会出现如下错误:
Role = 'user1.Role' threw an exception of type 'System.ObjectDisposedException'
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
为了绕过这个问题,我决定修改我的方法,以便告诉它在我需要导航属性的时候,可以预先加载它们。修改之后,我在DAL中的方法如下:
public User User(string email, bool loadRelationships)
{
User user = null;
if (!loadRelationships)
{
user = (from p in dbContext.Users where p.Email.Equals(email) select p).FirstOrDefault<User>();
}
else {
user = (from p in dbContext.Users.Include("Role").Include("Status") select p).FirstOrDefault<User>();
}
return user;
}
有了这个修改,问题仍然存在。我没有访问相关实体导航实体的权限…例如,如果一个角色类型有一个权限集合,如果我想这样做:
User user1 = UserManager("test@test.com");
foreach(Permission perm in user1.Role.Permissions)
Console.WriteLine(perm.Name); => here i'd get an error like the one mentioned earlier.
当POCO连接到数据库上下文时,延迟加载工作正常。是否有一种机制或策略可以像在我的场景中那样用于加载导航属性?
谢谢您。