【发布时间】:2014-11-29 22:25:33
【问题描述】:
这是我第一次使用 Entity Framework 6.1(代码优先)。我一直遇到一个问题,即我的导航属性在我不希望它们为空时为空。我已启用延迟加载。
我的实体如下所示:
public class Ask
{
public Ask()
{
this.quantity = -1;
this.price = -1;
}
public int id { get; set; }
public int quantity { get; set; }
public float price { get; set; }
public int sellerId { get; set; }
public virtual User seller { get; set; }
public int itemId { get; set; }
public virtual Item item { get; set; }
}
它有以下映射器:
class AskMapper : EntityTypeConfiguration<Ask>
{
public AskMapper()
{
this.ToTable("Asks");
this.HasKey(a => a.id);
this.Property(a => a.id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(a => a.id).IsRequired();
this.Property(a => a.quantity).IsRequired();
this.Property(a => a.price).IsRequired();
this.Property(a => a.sellerId).IsRequired();
this.HasRequired(a => a.seller).WithMany(u => u.asks).HasForeignKey(a => a.sellerId).WillCascadeOnDelete(true);
this.Property(a => a.itemId).IsRequired();
this.HasRequired(a => a.item).WithMany(i => i.asks).HasForeignKey(a => a.itemId).WillCascadeOnDelete(true);
}
}
具体来说,问题是我有一个 Ask 对象,该对象具有正确设置的 itemId(它确实对应于数据库中的 Item),但导航属性 item 为空,并且作为结果我最终得到一个 NullReferenceException。当我尝试访问a.item.name时,下面的代码中会抛出异常:
List<Ask> asks = repo.GetAsksBySeller(userId).ToList();
List<ReducedAsk> reducedAsks = new List<ReducedAsk>();
foreach (Ask a in asks)
{
ReducedAsk r = new ReducedAsk() { id = a.id, sellerName = a.seller.username, itemId = a.itemId, itemName = a.item.name, price = a.price, quantity = a.quantity };
reducedAsks.Add(r);
}
令人困惑的是,seller 导航属性在那里工作正常,我在“用户”实体及其映射器中找不到任何不同的做法。
我有一个重新创建它的测试,但它通过了,没有任何问题:
public void canGetAsk()
{
int quantity = 2;
int price = 10;
//add a seller
User seller = new User() { username = "ted" };
Assert.IsNotNull(seller);
int sellerId = repo.InsertUser(seller);
Assert.AreNotEqual(-1, sellerId);
//add an item
Item item = new Item() { name = "fanta" };
Assert.IsNotNull(item);
int itemId = repo.InsertItem(item);
Assert.AreNotEqual(-1, itemId);
bool success = repo.AddInventory(sellerId, itemId, quantity);
Assert.AreNotEqual(-1, success);
//add an ask
int askId = repo.InsertAsk(new Ask() { sellerId = sellerId, itemId = itemId, quantity = quantity, price = price });
Assert.AreNotEqual(-1, askId);
//retrieve the ask
Ask ask = repo.GetAsk(askId);
Assert.IsNotNull(ask);
//check the ask info
Assert.AreEqual(quantity, ask.quantity);
Assert.AreEqual(price, ask.price);
Assert.AreEqual(sellerId, ask.sellerId);
Assert.AreEqual(sellerId, ask.seller.id);
Assert.AreEqual(itemId, ask.itemId);
Assert.AreEqual(itemId, ask.item.id);
Assert.AreEqual("fanta", ask.item.name);
}
任何帮助将不胜感激;这几天让我发疯。
编辑:
数据库是 SQL Server 2014。
目前,我有一个共享上下文,实例化了上面的级别(我的数据库存储库层)。我应该为每个方法实例化一个新的上下文吗?或者在可能的最低级别(即每个数据库访问)实例化一个?例如:
public IQueryable<Ask> GetAsksBySeller(int sellerId)
{
using (MarketContext _ctx = new MarketContext())
{
return _ctx.Asks.Where(s => s.seller.id == sellerId).AsQueryable();
}
}
我的一些方法在 repo 层调用其他方法。让每个方法获取一个上下文,然后将其传递给它调用的任何方法会更好吗?
public IQueryable<Transaction> GetTransactionsByUser(MarketContext _ctx, int userId)
{
IQueryable<Transaction> buyTransactions = GetTransactionsByBuyer(_ctx, userId);
IQueryable<Transaction> sellTransactions = GetTransactionsBySeller(_ctx, userId);
return buyTransactions.Concat(sellTransactions);
}
然后,每当我从 repo 层调用任何内容时,我都可以实例化一个新的上下文:repo.GetTransactionsByUser(new MarketContext(), userId);
再次感谢您的帮助。我是新手,不知道哪种方法最好。
【问题讨论】:
-
上下文的生命周期是多少?这是什么数据库?
-
感谢您的浏览。我编辑了问题以提供更多信息。
标签: c# entity-framework-6 nullreferenceexception navigation-properties