2015-02-23 56 views
1

我有一个POCO类BankAccount这是public和所有的成员都public properties和导航属性设置为virtual这是什么EF6行为查找原因()不返回一个代理,但单()不会返回代理

实体框架6.1.2使用Find()方法从数据库正确加载它作为POCO。但是,据我所知,它应该返回一个Proxy类实例而不是POCO实例!实际上,当我使用Single()SingleOrDefault(),First()FirstOrDefault()代理类实例正确返回。

这是怎么回事,这是预期的行为,如果不是什么会导致这种情况发生?

下面是POCO类:

using System; 
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations; 
using System.ComponentModel.DataAnnotations.Schema; 
using System.Linq; 
using System.Runtime.Serialization; 

namespace AbcBankModels 
{ 
    //[DataContract] 
    [Table("BankAccount")] 
    public class BankAccount 
    { 
     [Key] 
     [Column(Order = 1)] 
     //[DataMember] 
     //[Range(0, 9999999)] 
     //[StringLength(7, MinimumLength = 7)] 
     //[Display(Name = "Account Number")] 
     public virtual string BankAccountId { get; set; } 

     [Key] 
     [Column(Order = 2)] 
     //[DataMember] 
     //[Range(0, 999999)] 
     //[StringLength(6, MinimumLength = 6)] 
     //[Display(Name = "Sort Code")] 
     public virtual string BankBranchId { get; set; } 

     //[DataMember] 
     public virtual BankBranch BankBranch { get; set; } 

     //[DataMember] 
     //[ForeignKey("ApplicationUser")] 
     public virtual string ApplicationUserId { get; set; } 

     //[DataMember] 
     public virtual User ApplicationUser { get; set; } 

     //[DataMember] 
     public virtual ICollection<BankCard> BankCardList { get; set; } 

     //[DataMember] 
     public virtual ICollection<BankTransaction> BankTransactionList { get; set; } 

     //[DataMember] 
     //[Display(Name = "Account Status")] 
     //[EnumDataType(typeof(EnumAccountStatus))] 
     public virtual EnumAccountStatus AccountStatus { get; set; } 

     //[DataMember] 
     //[Display(Name = "Account Type")] 
     //[EnumDataType(typeof(EnumBankAccountType))] 
     public virtual EnumBankAccountType AccountType { get; set; } 

     //[DataMember] 
     //[DataType(DataType.DateTime)] 
     //[Display(Name = "Date Account Opened")] 
     public virtual DateTime? AccountCreationDateTime { get; set; } 

     //[DataMember] 
     //[DataType(DataType.DateTime)] 
     //[Display(Name = "Date Account Closed")] 
     public virtual DateTime? AccountClosureDateTime { get; set; } 

     //[DataMember] 
     //[DataType(DataType.Currency)] 
     //[Display(Name = "Account Overdraft Limit")] 
     public virtual decimal AccountOverdraft { get; set; } 

     //[DataMember] 
     //[Display(Name = "Account Overdraft Interest Rate")] 
     public virtual decimal AccountOverdraftInterestRate { get; set; } 

     //[DataMember] 
     //[Display(Name = "Account Overdraft Usage Monthly Fee")] 
     public virtual decimal AccountOverdraftFacilityMonthlyCost { get; set; } 

     //[DataMember] 
     //[Display(Name = "Account Monthly Fee")] 
     public virtual decimal AccountMonthlyCost { get; set; } 

     //[DataMember] 
     //[Display(Name = "Account Interest Rate")] 
     public virtual decimal AccountInterestRate { get; set; } 

    } 
} 

这里是一个不会返回代理的方法:

public static BankAccount FindBankAccount(ApplicationDbContext applicationDbContext, string bankAccountId, string bankBranchId, string userId) 
    { 
     if (String.IsNullOrWhiteSpace(bankAccountId) || String.IsNullOrWhiteSpace(bankBranchId)) return null; 

     var bankAccount = applicationDbContext.BankAccountList.SingleOrDefault(a => a.BankAccountId == bankAccountId && a.BankBranchId == bankBranchId); 

     if (bankAccount == null) return null; 

     if (string.IsNullOrWhiteSpace(userId)) return bankAccount; 

     if (bankAccount.ApplicationUserId != userId) return null; 

     return bankAccount; 
    } 

这里是一个不返回代理的方法:

public static BankAccount FindBankAccount(ApplicationDbContext applicationDbContext, string bankAccountId, 
     string bankBranchId, string userId) 
    { 
     if (String.IsNullOrWhiteSpace(bankAccountId) || String.IsNullOrWhiteSpace(bankBranchId)) return null; 

     var bankAccount = applicationDbContext.BankAccountList.Find(bankAccountId, bankBranchId); 

     if (bankAccount == null) return null; 

     if (string.IsNullOrWhiteSpace(userId)) return bankAccount; 

     if (bankAccount.ApplicationUserId != userId) return null; 

     return bankAccount; 
    } 

回答

1

如果您的上下文在您查询的那一刻已经使用该密钥跟踪了非代理BankAccount,则可能会发生这种情况它。

奇怪的是,尽管First和Single总是查询数据库,但它们应该返回与Find相同的实体。

例如,如果您有运行该代码单元测试:

 Foo nonProxy = new Foo { Id = 4, Name = "Foo 4" }; // values correspond to an existing entity in db 
     ApplicationDbContext ctx = new ApplicationDbContext();   
     ctx.Foos.Attach(nonProxy); 
     Assert.AreSame(nonProxy, ctx.Foos.Find(nonProxy.Id)); 
     Assert.AreSame(nonProxy, ctx.Foos.First(c => c.Name == "Foo 4")); 
     Assert.AreSame(nonProxy, ctx.Foos.FirstOrDefault(c => c.Name == "Foo 4")); 
     Assert.AreSame(nonProxy, ctx.Foos.Single(c => c.Name == "Foo 4")); 
     Assert.AreSame(nonProxy, ctx.Foos.SingleOrDefault(c => c.Name == "Foo 4")); 

     ctx = new ApplicationDbContext(); 
     Foo proxy = ctx.Foos.Find(nonProxy.Id); 
     Assert.AreSame(proxy, ctx.Foos.Find(nonProxy.Id)); 
     Assert.AreSame(proxy, ctx.Foos.First(c => c.Name == "Foo 4")); 
     Assert.AreSame(proxy, ctx.Foos.FirstOrDefault(c => c.Name == "Foo 4")); 
     Assert.AreSame(proxy, ctx.Foos.Single(c => c.Name == "Foo 4")); 
     Assert.AreSame(proxy, ctx.Foos.SingleOrDefault(c => c.Name == "Foo 4")); 

,那么它应该没有错误运行。在上下文跟踪具有相同键的实体之后,它们都返回对同一对象的引用。

参考Querying/Finding Entities

// Query for the Blog named ADO.NET Blog 
var blog = context.Blogs.Where(b => b.Name == "ADO.NET Blog").FirstOrDefault(); 

当结果被从数据库返回的,不存在的背景下, 对象附加到上下文。如果对象已经在 上下文中,则返回现有对象(该条目中对象属性的当前和原始值 不会被数据库值覆盖 )。

所以,你可能正在使用中的情况下已经有一个非代理实体与关键上下文跟踪查找,或者你在代码中的某个地方使用它之前禁用Configuration.ProxyCreationEnabled。可能还有用:DbSet.Find Method

相关问题