我试图使用多对多关系填充引用表实体的子实体。
我有3个表:地址,成员和成员地址。地址和成员各有一个MemberAddresses集合。 MemberAddresses具有一个带有复合键的Address和Member对象。以下是相关映射:
地址
HasMany(x => x.MemberAddresses).WithRequired(x => x.Address).HasForeignKey(x => x.AddressId);
成员
HasMany(x => x.MemberAddresses).WithRequired(x => x.Member).HasForeignKey(x => x.MemberId);
MemberAddresses
HasRequired(rp => rp.Member).WithMany(x => x.MemberAddresses).HasForeignKey(rp => rp.MemberId);
当我着手执行以下操作时,我没有将任何子对象加载到Local扩展中(即Address和Member都为null):
_context.MemberAddresses.Include(rp => rp.Address).Where(rp => rp.MemberId == member.MemberId).Load();
有趣的是,EF的输出SQL正在执行正确的提取(我对SQL Server进行了检查)。如果我尝试使用带有ToList()的linq查询,它将按预期工作。它似乎是特定加载不起作用,并且不会填充子对象。
修改 为了更加清晰,我尝试使用简单的linq查询语法来实现相同的结果:
var results = (from ma in _context.MemberAddresses
where ma.MemberId == parentMember.MemberId
select ma).Include(x => x.Address).Include(x => x.Member).ToList();
这可以使用完全填充的MemberAddresses列表填充结果。但是,它没有被添加到_context.MemberAddresses.Local实例中。
更奇怪的是,如果我首先使用linq查询,然后执行上面的加载线,结果现在从内存中删除子对象。也就是说,它仍然具有两个子表的ID,但丢失了子对象实例。
答案 0 :(得分:0)
我无法重复使用Load()和枚举结果的任何差异。
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
namespace Ef6Test
{
public class Address
{
public int Id { get; set; }
public virtual ICollection<MemberAddress> MemberAddresses { get; } = new HashSet<MemberAddress>();
}
public class Member
{
public int Id { get; set; }
public virtual ICollection<MemberAddress> MemberAddresses { get; } = new HashSet<MemberAddress>();
}
public class MemberAddress
{
public Address Address { get; set; }
[Key( ), Column(Order =0)]
public int AddressId { get; set; }
public Member Member{ get; set; }
[Key(), Column(Order = 1)]
public int MemberId{ get; set; }
}
class Db : DbContext
{
public DbSet<Address> Address { get; set; }
public DbSet<Member> Member{ get; set; }
public DbSet<MemberAddress> MemberAddresses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
class Program
{
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<Db>());
using (var db = new Db())
{
db.Database.Initialize(true);
var m = new Member();
for (int i = 0; i < 10; i++)
{
var a = new Address();
var ma = new MemberAddress();
ma.Address = a;
ma.Member = m;
db.Address.Add(a);
db.MemberAddresses.Add(ma);
}
db.Member.Add(m);
db.SaveChanges();
}
Console.WriteLine("Enumerating Include Query");
using (var db = new Db())
{
db.Database.Log = m => Console.WriteLine(m);
var list = db.MemberAddresses.Include(rp => rp.Address).Where(rp => rp.MemberId < 10).ToList();
foreach (var e in db.ChangeTracker.Entries())
{
Console.WriteLine(e.Entity.GetType().Name);
}
var a = db.ChangeTracker.Entries<MemberAddress>().First();
Console.WriteLine($"Address IsLoaded: {a.Reference<Address>("Address").IsLoaded}");
Console.WriteLine($"Member Local {db.Member.Local.Count} items");
foreach (var member in db.Member.Local)
{
Console.WriteLine($"Member {member.Id}");
}
Console.WriteLine($"MemberAddress Local {db.MemberAddresses.Local.Count} items");
foreach (var ma in db.MemberAddresses.Local)
{
Console.WriteLine($"MemberAddress {ma.MemberId},{ma.AddressId}");
}
Console.WriteLine($"Address Local {db.Address.Local.Count} items");
foreach (var ad in db.Address.Local)
{
Console.WriteLine($"Address {ad.Id}");
}
}
Console.WriteLine("Using Load()");
using (var db = new Db())
{
db.Database.Log = m => Console.WriteLine(m);
db.MemberAddresses.Include(rp => rp.Address).Where(rp => rp.MemberId < 10).Load();
foreach (var e in db.ChangeTracker.Entries())
{
Console.WriteLine(e.Entity.GetType().Name);
}
var a = db.ChangeTracker.Entries<MemberAddress>().First();
Console.WriteLine($"Address IsLoaded: {a.Reference<Address>("Address").IsLoaded}");
Console.WriteLine($"Member Local {db.Member.Local.Count} items");
foreach (var member in db.Member.Local)
{
Console.WriteLine($"Member {member.Id}");
}
Console.WriteLine($"MemberAddress Local {db.MemberAddresses.Local.Count} items");
foreach (var ma in db.MemberAddresses.Local)
{
Console.WriteLine($"MemberAddress {ma.MemberId},{ma.AddressId}");
}
Console.WriteLine($"Address Local {db.Address.Local.Count} items");
foreach (var ad in db.Address.Local)
{
Console.WriteLine($"Address {ad.Id}");
}
}
Console.WriteLine("Hit any key to exit");
Console.ReadKey();
}
}
}
输出
Enumerating Include Query
Opened connection at 12/6/2017 8:33:59 AM -06:00
SELECT
[Extent1].[AddressId] AS [AddressId],
[Extent1].[MemberId] AS [MemberId]
FROM [dbo].[MemberAddresses] AS [Extent1]
WHERE [Extent1].[MemberId] < 10
-- Executing at 12/6/2017 8:34:00 AM -06:00
-- Completed in 15 ms with result: SqlDataReader
Closed connection at 12/6/2017 8:34:00 AM -06:00
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
Address IsLoaded: True
Member Local 0 items
MemberAddress Local 10 items
MemberAddress 1,1
MemberAddress 1,2
MemberAddress 1,3
MemberAddress 1,4
MemberAddress 1,5
MemberAddress 1,6
MemberAddress 1,7
MemberAddress 1,8
MemberAddress 1,9
MemberAddress 1,10
Address Local 10 items
Address 1
Address 2
Address 3
Address 4
Address 5
Address 6
Address 7
Address 8
Address 9
Address 10
Using Load()
Opened connection at 12/6/2017 8:34:00 AM -06:00
SELECT
[Extent1].[AddressId] AS [AddressId],
[Extent1].[MemberId] AS [MemberId]
FROM [dbo].[MemberAddresses] AS [Extent1]
WHERE [Extent1].[MemberId] < 10
-- Executing at 12/6/2017 8:34:00 AM -06:00
-- Completed in 8 ms with result: SqlDataReader
Closed connection at 12/6/2017 8:34:00 AM -06:00
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
MemberAddress
Address_B9AEC76E2DAA985CBBFB722E4D5F60354D0FC4633617474BEE39DD928330C226
Address IsLoaded: True
Member Local 0 items
MemberAddress Local 10 items
MemberAddress 1,1
MemberAddress 1,2
MemberAddress 1,3
MemberAddress 1,4
MemberAddress 1,5
MemberAddress 1,6
MemberAddress 1,7
MemberAddress 1,8
MemberAddress 1,9
MemberAddress 1,10
Address Local 10 items
Address 1
Address 2
Address 3
Address 4
Address 5
Address 6
Address 7
Address 8
Address 9
Address 10
Hit any key to exit