我有两个实体:
public class Booking
{
[Key]
public int Id { get; set; }
public int RoomId { get; set; }
[ForeignKey("RoomId")]
public Room Room { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string DocumentNumber { get; set; }
public string ContactPhone { get; set; }
}
public class Room
{
[Key]
public int RoomId { get; set; }
public int Number { get; set; }
public int Size { get; set; }
public bool HasBalcony { get; set; }
public int Beds_1 { get; set; }
public int Beds_2 { get; set; }
public double DayPrice { get; set; }
public List<Booking> Bookings { get; set; }
...
public int BookingsCount()
{
return Bookings.Count;
}
public bool IsFree(DateTime dateTime)
{
MessageBox.Show(BookingsCount().ToString());
return true;
}
}
和DbContext:
public class HotelContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
public DbSet<Room> Rooms { get; set; }
public DbSet<Booking> Bookings { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Booking>()
.HasRequired(b => b.Room)
.WithMany(r => r.Bookings)
.HasForeignKey(b => b.RoomId);
}
}
当调用MessageBox.Show时,我得到异常:类型&#39; System.NullReferenceException&#39;的未处理异常。发生在Hotel.exe
当我尝试访问Room :: Bookings时,列表始终为null。 “预订”表中有一行,“房间”表中有多行。 如何将所有预订加载到Room对象中?
答案 0 :(得分:2)
取决于你在学习曲线中的位置,但有些事情很突出
<强>首先强>
您要么通过 FluentApi 或 Annotations 创建关系,而不是两者
IE中。你在房间实体上有这个
[ForeignKey("RoomId")]
这很流利
modelBuilder.Entity<Booking>()
.HasRequired(b => b.Room)
.WithMany(r => r.Bookings)
.HasForeignKey(b => b.RoomId);
您需要选择其中一个,否则您可能会在Booking
RoomId
和Room_Id
其次
如果您希望延迟加载 bookings
,则需要Bookings
收集Virtual
public virtual List<Booking> Bookings { get; set; }
<强>最后强>
访问您的数据(假设您的连接字符串是正确的)
using(var db = new HoteContext())
{
var rooms = db.Rooms.Include(x => x.Bookings).ToList();
}
注意 :虽然EF Lazy加载关系,但您可能需要确保已包含Room->Booking
关系
答案 1 :(得分:1)
请考虑以下代码。
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
using (MyDbContext dbContext = new MyDbContext())
{
dbContext.Departments.Add(new Department()
{
Name = "Some Department1",
Employees=new List<Employee>()
{
new Employee() { Name = "John Doe" }
}
});
dbContext.SaveChanges();
var department = dbContext.Departments.FirstOrDefault(d => d.Name == "Some Department1");
if (department.Employees != null)
{
foreach (var item in department.Employees)
{
Console.WriteLine(item.Name);
}
}
}
}
}
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
public List<Employee> Employees { get; set; }
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
public class MyDbContext : DbContext
{
public DbSet<Department> Departments { get; set; }
public DbSet<Employee> Employees { get; set; }
}
}
如果你有上面的代码,那么控件将不会进入条件,因为department.Employees为null。现在,按如下方式更改Department实体。
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<Employee> Employees { get; set; }
}
现在你应该能够看到控制进入if条件并输出员工姓名。
这称为延迟加载。
如果您想急切加载,则不必将虚拟添加到该媒体资源中。您可以按如下方式包含属性。
var department = dbContext.Departments.Include(d => d.Employees).FirstOrDefault(d => d.Name == "Some Department1");
现在您可以看到员工姓名正在输出。
答案 2 :(得分:0)
您的设计绝对会遇到性能问题。
EF的诱惑是将对象模型完全映射到数据库,让EF在幕后为你做所有的魔术。但是你需要考虑的是在任何时候只从db获得你需要的东西。否则你会得到各种笛卡尔产品问题。我强烈建议您自己获取一份Hibernating Rhino的EF Profiler或类似内容,这样您就可以在运行时静态分析代码以解决EF性能问题(并查看它生成的SQL)。对于这个你想要的是一个专门建立的DB调用来获取计数。否则会发生什么事情,你将拉出整个预订表,然后让C#给你计数。只有你想对整个列表做些什么才有意义。有两种选择:
1)针对预订表创建一个VIEW并将其映射到EF。该视图看起来像SELECT ROOMS.ROOMID, COUNT(*)
- 您将此视图映射到您的模型并 voila 现在您有一个按房间(id)计算的列表,您可以单独使用它们或将其总结获得所有房间的总数。如果您在10个房间中有1,000个预订,那么您只能从数据库中返回10行。而对于您的设计,您将使用所有字段撤回所有1,000个预订,然后使用C#进行过滤。坏juju。
2)架构和概念上更简单的方法是直接进行查询(显然这只会从db中返回一个int
):
public int BookingsCount()
{
int count = 0;
try
{
using (var context = new HotelContext())
{
var sql ="SELECT COUNT(*) FROM Bookings WHERE ROOMID=" + this.RoomId;
count = context.Database.SqlQuery<int>(sql).First();
}
} catch (Exception ex)
{
// Log your error, count will be 0 by default
}
return count;
}
答案 3 :(得分:-1)
一个简单的解决方案是将预订属性设为虚拟。
public class Room
{
[Key]
public int RoomId { get; set; }
public int Number { get; set; }
public int Size { get; set; }
public bool HasBalcony { get; set; }
public int Beds_1 { get; set; }
public int Beds_2 { get; set; }
public double DayPrice { get; set; }
public virtual List<Booking> Bookings { get; set; }
}
有关实体框架加载相关实体的更多信息, https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx