ライブラリに単一の DbContext があり、エンティティとその構成が流暢な API に含まれています。
この同じコンテキストを 2 つの異なるプロジェクトで使用しています。1 つ目はテスト プロジェクトで、2 つ目は単純なコンソール アプリケーションです。
次のような関係の一部を含むクエリを実行します。
var vacancies = (from v in ctx.Vacancies
.Include("Categories")
.Include("Levels")
.Include("Contracts")
.Include("JobTypes"));
奇妙なことに、コンソール アプリケーションは完全に動作しますが、単体テストが突然間違ったテーブルを検索し始めます。
私がそれらを見ると、両方のアプリケーションが非常に異なるクエリを生成します。
私はEF5 atmを使用していますが、この問題の原因についての手がかりが1つもないまま、数日間これに固執しています。
編集:ポイントは、私は別のクエリを実行しないことです。また、コンテキストのみを持ち、実行時に確認した1つの接続文字列のみが適切なデータベースに接続します。
私が言えることは、流暢なAPIは、本来のようにコードにうまくヒットしても、ユニットテストでは効果がないように感じるということだけです。
public class SchedulerContext : BaseContext<SchedulerContext>{
public DbSet<Click> Clicks { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<ContractType> Contracts { get; set; }
public DbSet<JobType> JobTypes { get; set; }
public DbSet<Level> Levels { get; set; }
public DbSet<ExternalMapping> ExternalMappings { get; set; }
public DbSet<GeoName> GeoNames { get; set; }
public DbSet<GeoAlternateName> GeoAlternateNames { get; set; }
public DbSet<Trigger> JobTriggers { get; set; }
public DbSet<RegistryValue> RegistryValues { get; set; }
public DbSet<JobResult> JobResults { get; set; }
public DbSet<JobInfo> JobInfo { get; set; }
public DbSet<JobError> JobErrors { get; set; }
public DbSet<JobNotification> JobNotifications { get; set; }
public DbSet<Company> Customers { get; set; }
public DbSet<Vacancy> Vacancies { get; set; }
public SchedulerContext() {
//this.Configuration.ProxyCreationEnabled = false;
//this.Configuration.LazyLoadingEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Configurations.Add(new VacancyEntityTypeConfiguration());
base.OnModelCreating(modelBuilder);
}
}
それが私の文脈です。
そして私のエンティティ構成:
public class VacancyEntityTypeConfiguration : EntityTypeConfiguration<Vacancy> {
public VacancyEntityTypeConfiguration() {
this.HasMany(c => c.Levels).
WithMany().
Map(
m => {
m.ToTable("VacancyLevels");
});
this.HasMany(c => c.Categories).
WithMany().
Map(
m => {
m.ToTable("VacancyCategories");
});
this.HasMany(c => c.Contracts).
WithMany().
Map(
m => {
m.ToTable("VacancyContractTypes");
});
this.HasMany(c => c.Jobtypes).
WithMany().
Map(
m => {
m.ToTable("VacancyJobTypes");
});
}
}
そして、問題を示す正確な方法。
public List<Vacancy> GetVacanciesForCustomer(Company customer, bool onlineInclusive) {
using (var ctx = new JHSchedulerContext.SchedulerContext()) {
var vacancies = (from v in ctx.Vacancies.Include("Categories").Include("Levels").Include("Contracts").Include("JobTypes") where v.SourceSite == customer.SourceSite && (v.Online || onlineInclusive == false) select v).ToList();
return vacancies.ToList();
}
}
そして欠員クラス:
public class Vacancy {
public Vacancy()
{
this.Language = "";
}
[SolrUniqueKey("id")]
[Key]
[Required]
public int Id { get; set; }
[StringLength(50, ErrorMessage = "Maximum length 50 characters")]
public string ExternalId { get; set; }
[SolrField("title")]
[StringLength(1024, ErrorMessage = "Maximum length 1024 characters")]
public string Title { get; set; }
[SolrField("company")]
[StringLength(1024, ErrorMessage = "Maximum length 1024 characters")]
public string Company { get; set; }
[StringLength(4096, ErrorMessage = "Maximum length 4096 characters")]
public string CompanyText { get; set; }
[SolrField("location")]
[StringLength(1024, ErrorMessage = "Maximum length 1024 characters")]
public string Location { get; set; }
[SolrField("url")]
[StringLength(1024, ErrorMessage = "Maximum length 1024 characters")]
public string Url { get; set;}
[SolrField("source")]
[StringLength(1024, ErrorMessage = "Maximum length 1024 characters")]
public string SourceSite { get; set; }
private string text;
[SolrField("text")]
[StringLength(4096, ErrorMessage = "Maximum length 4096 characters")]
public string Text {
get {
return StringHelper.TruncateAtWord(text, 500);
//return new String(text.Take(500).ToArray());
//return text.Substring(text.Length < 900 ? 0 : (text.Length / 2), (int)Math.Min(text.Length, 500));
}
set{
text = value;
}
}
[StringLength(4096, ErrorMessage = "Maximum length 4096 characters")]
public string TextProfile { get; set; }
[StringLength(4096, ErrorMessage = "Maximum length 4096 characters")]
public string TextOffer { get; set; }
[NotMapped]
[ScriptIgnore]
public SqlGeography Coordinate {
get
{
if (Latitude.HasValue && Longitude.HasValue)
return SqlGeography.Point(Latitude.Value, Longitude.Value, 4326);
else
return null;
}
}
[SolrField("coordinate_0_coordinate")]
public double? Latitude { get; set; }
[SolrField("coordinate_1_coordinate")]
public double? Longitude { get; set; }
[StringLength(1024, ErrorMessage = "Maximum length 1024 characters")]
public string NormalizedLocation { get; set; }
public DateTime? ScrapedDate { get; set; }
[SolrField("insertdate")]
public DateTime? ImportDate { get; set; }
public DateTime? ExpireDate { get; set; }
[NotMapped]
public string DaysAgo {
get {
if (ImportDate != null)
return (DateTime.Now - (DateTime)ImportDate).Days.ToString();
else {
return "N/A";
}
}
}
[SolrField("category")]
public ICollection<string> CategoryNames {
get { return Categories != null ? Categories.Select(c => c.Name).ToList() : null; }
}
[SolrField("level")]
public ICollection<string> LevelNames {
get { return Levels != null ? Levels.Select(l => l.Name).ToList() : null; }
}
[SolrField("contract")]
public ICollection<string> ContractNames {
get { return Contracts != null ? Contracts.Select(c => c.Name).ToList() : null; }
}
[SolrField("time")]
public ICollection<string> JobTypeNames {
get { return Jobtypes != null ? Jobtypes.Select(c => c.Name).ToList() : null; }
}
public string ContactName { get; set; }
[Required]
public bool Online { get; set; }
[NotMapped]
public int? Distance { get; set; }
public string Language { get; set; }
public string PriorityType { get; set; }
public int NumClicks { get; set; }
[NotMapped]
public string GridContactName {
get{
return string.Format("{0} (Total Clicks:{1})",ContactName,NumClicks);
}
}
public virtual ICollection<Level> Levels { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<ContractType> Contracts { get; set; }
public virtual ICollection<JobType> Jobtypes { get; set; }
public override string ToString() {
return string.Format("Id={0} ExternalId={1} Title={2} Company={3} Location={4} Url={5} SourceSite={6} Text={7} NormalizedLocation={8} InsertDate={9} ImportDate={10} DaysAgo={11}",Id, ExternalId,Title,Company,Location,Url, SourceSite,Text,NormalizedLocation,ScrapedDate,ImportDate,DaysAgo);
}
}
そして Level クラス (他のすべての関係クラスは同じ構造 (name,id) を持っています:
public class Level {
[Key]
[Required]
public int Id { get; set; }
[Required]
[StringLength(100, ErrorMessage = "Maximum length 100 characters")]
public string Name { get; set; }
public override string ToString() {
return string.Format("Id={0} Name={1}", Id, Name);
}
}
データベースへの接続に関する限り、両方が同じデータベースに接続していることを確認したことを信じてください.まだまったく同じ問題がありました)。
明確にするために:ユニットテストはテーブルを探します:CategoryVacancy。コンソール アプリケーションまたは Windows サービスでさえ、これを使用して正しいテーブルを探します: VacancyCategories.