【发布时间】:2010-09-13 14:03:41
【问题描述】:
我启动了一个 ASP.net Web 项目应用程序来了解如何使用 EF4。在我的项目中,我定义了 3 层(DAL => Entity Framework 4,BLL => 业务逻辑层,UI)。 BLL 和 DAL 共享使用 EF4 的模板特性生成的 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) 实例化一个类并调用返回 User 的 GetUserByEmailFromDAL(string email) 方法。
李> DAL=> 在 GetUserByEmailFromDAL(string email) 我实例化一个上下文,查询用户并返回它。
问题在于,因为只有 DAL 知道上下文并且它在退出函数后被释放,所以 POCO 的导航关系为空,我无法访问它们的任何属性。
如果我执行 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 附加到数据库上下文时,延迟加载有效。是否有一种机制或策略可用于加载导航属性,例如我的场景?
谢谢。
【问题讨论】:
标签: navigation load entity-framework-4 properties poco