2013-07-19 58 views
1

在嘗試編寫一些乾淨的模型類庫時,我使用的是EF5 Code First。使用EntityTypeConfiguration將各種屬性映射到託管在SQL Server 2005服務器實例上的2個VIEWS列中。EF5代碼首先在DbSet查詢中執行意外的JOIN

注意:我知道有一些不良的表列命名正在進行,但由於它是現有的數據庫,因此我必須應對此問題。請原諒我。

做管道後,我可以查詢客戶賬戶...

var context = new Data.EntityContext(); 
public IQueryable<ClientAccount> GetClients(List<string> usernameOrEmail) 
{ 
    return context.ClientAccount.Where(p => usernameOrEmail.Contains(p.UserName) || usernameOrEmail.Contains(p.Email)).Include("Company").AsQueryable(); 
} 

...匹配的客戶端返回,其中包括公司的詳細信息。

但是,當試圖僅獲取公司列表時,結果包含大量重複項。

var companies = data.Companies.Where(c => c.IsActive).OrderBy(c => c.Name); 

使用SQL Server Profiler中我發現,對我的原因尚不清楚,發動機配備了一個LEFT OUTER JOIN,以包括客戶端的用戶id以及:

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Company] AS [Company], 
    [Extent1].[Address] AS [Address], 
    [Extent1].[AddressSuffix] AS [AddressSuffix], 
    [Extent1].[Zip] AS [Zip], 
    [Extent1].[City] AS [City], 
    [Extent1].[State] AS [State], 
    [Extent1].[CountryName] AS [CountryName], 
    [Extent1].[Telephone] AS [Telephone], 
    [Extent1].[Fax] AS [Fax], 
    [Extent1].[Url] AS [Url], 
    [Extent1].[Latitude] AS [Latitude], 
    [Extent1].[Longitude] AS [Longitude], 
    [Extent1].[isPublic] AS [isPublic], 
    [Extent1].[active] AS [active], 
    [Extent1].[parent] AS [parent], 
    [Extent2].[userId] AS [userId] 
FROM [dbo].[VIEW_CompaniesCountryContinent] AS [Extent1] 
    LEFT OUTER JOIN [dbo].[PassportAccounts] AS [Extent2] ON ([Extent2].[companyId] IS NOT NULL) AND ([Extent1].[Id] = [Extent2].[companyId]) 
WHERE 1 = [Extent1].[active] 

我不知道爲什麼,因爲我沒有鏈接到公司模式的客戶。 VIEW不包括用戶表,只針對公司表。

很明顯,我錯過了某些東西,我希望你能讓我回到正軌。 下面你會找到關於模型,上下文和實體規範的一些細節。 謝謝!

代碼信息:

模式是相當簡單的...

public class ClientAccount : IUserAccount 
{ 
    public ClientAccount() { } 

    [Key] 
    public int ClientId { get; set; } 

    [DisplayName("User Name")] 
    public string UserName { get; set; } 

    [DisplayName("First Name")] 
    public string FirstName { get; set; } 

    [DisplayName("Last Name")] 
    public string LastName { get; set; } 

    [DisplayName("Job Title")] 
    public string JobTitle { get; set; } 

    [DisplayName("Company")] 
    public virtual Company Company { get; set; } 

    [DisplayName("Direct Phone")] 
    public string PhoneDirect { get; set; } 

    [DisplayName("Mobile phone")] 
    public string PhoneMobile { get; set; } 

    [DisplayName("Registration Date")] 
    public DateTime DateRegistered { get; set; } 

    [DisplayName("Last Login")] 
    public DateTime LastLogin { get; set; } 

    [EmailAddress] 
    [DisplayName("Email")] 
    public string Email { get;set; } 

    public bool IsApproved { get; set; } 
    public bool IsActive { get; set; } 
    public bool IsLockedOut { get { return !IsActive; } } 
    public bool IsOnline 
    { 
     get { return (LastLogin.AddMinutes(10) > DateTime.Now); } 
    } 

    public DateTime LastActivityAt { get; set; } 
} 

public class Company 
{ 
    [Key] 
    public int ID { get; set; } 

    public string Name { get; set; } 

    public string Address { get; set; } 
    public string Address2 { get; set; } 

    public string Zip { get; set; } 
    public string City { get; set; } 
    public string State { get; set; } 

    public string Country { get; set; } 

    public string Telephone { get; set; } 
    public string Fax { get; set; } 
    public string Url { get; set; } 

    public string TimeZone { get; set; } 
    public Coordinate Coordinate { get; set; } 

    public bool IsPublic { get; set; } 
    public bool IsActive { get; set; } 

    public int ParentCompanyId { get; set; } 

} 

public class Coordinate 
{  
    public decimal? Latitude { get; set; } 
    public decimal? Longitude { get; set; } 
} 

到目前爲止,沒有什麼特別的(?右)。 的的DbContext

public class EntityContext : DbContext 
{ 

    public EntityContext() : base("Name=EntityContext") 
    { 
     Database.SetInitializer<EntityContext>(null); 
    } 

    public EntityContext(string connectionString) 
     : base(connectionString) 
    { 
     Database.SetInitializer<EntityContext>(null); 
    } 

    public DbSet<ClientAccount> ClientAccount { get; set; } 
    public DbSet<Company> Companies { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Configurations.Add(new CompanyConfiguration()); 
     modelBuilder.Configurations.Add(new ClientAccountConfiguration()); 

     base.OnModelCreating(modelBuilder); 
    } 
} 

而且EntityTypeConfigurations ...

public class ClientAccountConfiguration : EntityTypeConfiguration<ClientAccount> 
{ 
    public ClientAccountConfiguration() 
     : base() 
    { 
     HasKey(p => p.ClientId); 

     ToTable("ClientAccounts"); // VIEW ClientAccounts 

     Property(p => p.ClientId) 
      .HasColumnName("userId") 
      .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity) 
      .IsRequired(); 

     Property(p => p.Email) 
      .HasColumnName("userEmail") 
      .IsRequired(); 

     Property(p => p.UserName) 
      .HasColumnName("userLogin") 
      .IsRequired(); 

     Property(p => p.FirstName).HasColumnName("userFirstName"); 
     Property(p => p.LastName).HasColumnName("userLastName"); 
     Property(p => p.PhoneDirect).HasColumnName("userPhoneDirect"); 
     Property(p => p.PhoneMobile).HasColumnName("userPhoneMobile"); 

     Property(p => p.JobTitle) 
      .HasColumnName("userPosition"); 

     HasOptional(p => p.Company) 
      .WithOptionalDependent() 
      .Map(p => p.MapKey("companyId")); 

     Property(p => p.IsApproved).HasColumnName("Employed"); 
     Property(p => p.IsActive).HasColumnName("active"); 
     Property(p => p.LastActivityAt).HasColumnName("updated"); 
     Property(p => p.LastLogin).HasColumnName("LastLogin").IsOptional(); 
     Property(p => p.DateRegistered).HasColumnName("created"); 

    } 
} 

public class CompanyConfiguration : EntityTypeConfiguration<Company> 
{ 
    public CompanyConfiguration() 
    { 
     this.HasKey(c => c.ID); 


     this.ToTable("VIEW_CompaniesCountryContinent"); 
     this.Property(c => c.ID) 
      .HasColumnName("Id") 
      .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 

     this.Property(c => c.Name) 
      .HasColumnName("Company") 
      .IsRequired(); 

     this.Property(c => c.Address).HasColumnName("Address"); 
     this.Property(c => c.Address2).HasColumnName("AddressSuffix"); 
     this.Property(c => c.Country).HasColumnName("CountryName"); 
     this.Property(c => c.City).HasColumnName("City"); 

     this.Property(c => c.Zip).HasColumnName("Zip"); 
     this.Property(c => c.State).HasColumnName("State"); 

     this.Property(c => c.Coordinate.Latitude).HasColumnName("Latitude"); 
     this.Property(c => c.Coordinate.Longitude).HasColumnName("Longitude"); 

     this.Property(c => c.TimeZone).HasColumnName("timezone"); 

     this.Property(c => c.IsPublic).HasColumnName("isPublic"); 
     this.Property(c => c.IsActive).HasColumnName("active"); 

     this.Property(c => c.ParentCompanyId).HasColumnName("parent"); 

    } 
} 
+0

什麼是'data'在'data.Companies.Where'?只是上下文? –

+0

順便說一句,在你給的sql中,你有'[Extent2]。[userId] AS [userId]'。它應該從哪裏來? 「var companies」是可查詢的嗎?如果是,那麼在哪裏以及如何使用? –

+0

@Raphael:是的,數據是上下文 sql是通過使用Sql Profiler獲得的,並且由EntityFramework(而不是我)生成。 userId是困惑我,不知何故EF執行此JOIN,但我不明白爲什麼。這絕不是公司模式的一部分。 –

回答

0

跟進由阿隆提供的解決方案。

執行此修復程序後,我很快遇到了無法更新ClientAccount對象的公司的問題。這很有意義,因爲模型不允許更新ClientAccount對象的CompanyId屬性。

外鍵屬性已包含在模型中,其次屬性名稱必須與它指向的對象的鍵屬性名稱匹配。這也解決了我的原始問題。 儘管它確實需要對(已經存在的)公司模型進行更改,這會對其他已使用公司類的項目產生影響。

的變化:

在我的模型,我添加了CompanyId財產和(在爲了匹配屬性名稱)更改從ID公司ID屬性CompanyId名稱:

public class ClientAccount : IUserAccount 
{ 
    public ClientAccount() { } 

    ... 

    public Nullable<int> CompanyId { get; set; } 

    [DisplayName("Company")] 
    public virtual Company Company { get; set; } 

    ... 
} 

public class Company 
{ 
    [Key] 
    public int CompanyId { get; set; } 

    public string Name { get; set; } 

    ... 

} 

在EntityTypeConfiguration中,我將新的CompanyId屬性映射到相應的數據庫列名稱,並且可以省略公司映射。

public class ClientAccountConfiguration : EntityTypeConfiguration<ClientAccount> 
{ 
    public ClientAccountConfiguration() 
     : base() 
    { 
     ... 

     Property(p => p.CompanyId).HasColumnName("companyId"); 

     /* 
     HasOptional(p => p.Company) 
      .WithOptionalDependent() 
      .Map(p => p.MapKey("companyId")); 
     */ 

     ... 
    } 
}