2015-02-23 4 views
1

У меня есть класс POCO BankAccount который public и все члены являются public properties и навигационные свойства установлены в virtual ,Что является причиной этого поведения EF6 Find() не возвращает прокси-сервер, но Single() делает возвращать прокси

Entity Framework 6.1.2 правильно загружает его из базы данных в виде POCO с использованием метода Find(). Однако, насколько мне известно, он должен возвращать экземпляр класса 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