1

TagオブジェクトのTagTypeが有効になるように、モデルに次の制約を作成しようとしています。有効なTagTypeは、OperatingCompanyIdがタグのWebサイトのOperatingCompanyIdと一致するものです。これは複雑に思えますが、ビジネスの観点からは理にかなっています。

運営会社にはウェブサイトがあります。ウェブサイトにはタグが含まれています。タグにはTagType(単数)があります。TagTypesは事業会社間で同じです。つまり、1つの事業会社が20のTagTypeと5つのWebサイトを持っている場合、それらの20のTagTypeはそれらの5つのWebサイトすべてで使用できるはずです。タグのTagTypeが別のOperatingCompanyに関連付けられていないことを確認したいと思います。

モデルでこの制約を作成するための最良の方法は何ですか?POCOを変更する必要がありますか、それともFluent APIを使用する必要がありますか?

前もって感謝します!

[Table("OperatingCompanies")]
public class OperatingCompany : ConfigObject
{
    public OperatingCompany()
    {
        WebSites = new List<WebSite>();
    }

    [Required(ErrorMessage = "Name is a required field for an operating company.")]
    [MaxLength(100, ErrorMessage = "Name cannot exceed 100 characters.")]
    public string Name { get; set; }

    public virtual ICollection<WebSite> WebSites { get; set; }
}

[Table("Websites")]
public class WebSite : ConfigObject
{
    public WebSite()
    {
        WebObjects = new List<WebObject>();
    }

    [Required(ErrorMessage = "URL is a required field for a web site.")]
    [MaxLength(100, ErrorMessage = "URL cannot exceed 100 characters for a web site.")]
    [RegularExpression(@"\b(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]*[-A-Za-z0-9+&@#/%=~_|]", ErrorMessage = "The value entered is not a valid URL.")]
    public string Url { get; set; }

    public OperatingCompany OperatingCompany { get; set; }

    [Required(ErrorMessage = "You must associate a web site with an operating company.")]
    public Guid OperatingCompanyId { get; set; }

    [InverseProperty("Website")]
    public virtual ICollection<WebObject> WebObjects { get; set; }
}

[Table("Tags")]
public class Tag : ConfigObject
{
    [Required(ErrorMessage = "Name is a required field for a tag.")]
    [MaxLength(100, ErrorMessage = "Name cannot exceed 100 characters for a tag.")]
    public string Name { get; set; }

    public TagType TagType { get; set; }

    [Required(ErrorMessage = "You must associate a tag with a tag type.")]
    public Guid TagTypeId { get; set; }

    public WebSite WebSite { get; set; }

    [Required(ErrorMessage = "You must associate a tag with a web site.")]
    public Guid WebSiteId { get; set; }
}

[Table("TagTypes")]
public class TagType : ConfigObject
{
    [Required(ErrorMessage = "Name is a required field for a tag.")]
    [MaxLength(100, ErrorMessage = "Name cannot exceed 100 characters for a tag type.")]
    public string Name { get; set; }

    public OperatingCompany OperatingCompany { get; set; }

    [Required(ErrorMessage = "You must associate a tag type with an operating company.")]
    public Guid OperatingCompanyId { get; set; }
}
4

3 に答える 3

2

この制約を適用する1つの方法は、EF4.1の新しいDbContextAPIの一部として導入された新しい検証機能を利用することです。カスタム検証ルールを記述して、特定の会社のWebサイトのタグタイプが、その会社の有効なタグタイプから選択されていることを確認できます。以下に、その方法を示します。

public abstract class ConfigObject
{
    public Guid Id { get; set; }
}

public class OperatingCompany : ConfigObject, IValidatableObject
{
    public string Name { get; set; }

    public virtual ICollection<WebSite> WebSites { get; set; }
    public virtual List<TagType> TagTypes { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var allTagTypes = (from w in WebSites from t in w.Tags select t.TagType);

        if (!allTagTypes.All(wtt => TagTypes.Exists(tt => tt.Id == wtt.Id)))
        {
            yield return new ValidationResult("One or more of the website's tag types don't belong to this company");
        }            
    }
}

public class WebSite : ConfigObject
{
    public string Url { get; set; }                
    public Guid OperatingCompanyId { get; set; }

    public virtual ICollection<Tag> Tags { get; set; }
    public OperatingCompany OperatingCompany { get; set; }                
}

public class Tag : ConfigObject
{
    public string Name { get; set; }
    public Guid TagTypeId { get; set; }
    public Guid WebSiteId { get; set; } 

    public TagType TagType { get; set; }               
    public WebSite WebSite { get; set; }
}

public class TagType : ConfigObject
{
    public string Name { get; set; }
    public Guid OperatingCompanyId { get; set; }

    public OperatingCompany OperatingCompany { get; set; }                
}

public class Context : DbContext
{
    public DbSet<OperatingCompany> OperatingCompanies { get; set; }
    public DbSet<WebSite> WebSites { get; set; }
    public DbSet<Tag> Tags { get; set; }
    public DbSet<TagType> TagTypes { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Tag>().HasRequired(t => t.WebSite)
                                  .WithMany(w => w.Tags)
                                  .HasForeignKey(t => t.WebSiteId)
                                  .WillCascadeOnDelete(false);
    }
}

その結果、EFはDbContext.SaveChanges()を呼び出すたびにその検証メソッドを呼び出してOperatingCompanyオブジェクトをデータベースに保存し、メソッドが検証エラーを返した場合、EFはスロー(およびトランザクションを中止)します。DbContextクラスのGetValidationErrorsメソッドを呼び出して、操作しているモデルオブジェクト内の検証エラーのリストを取得することにより、検証エラーを事前にチェックすることもできます。

ドメインモデルをMVCレイヤーのビューモデルとしても使用するため、MVCはこの検証ルールを認識して尊重し、コントローラーでModelStateを調べることで検証結果を確認できることにも注意してください。つまり、実際には2つの場所でチェックされます。1つはMVCによるプレゼンテーション層で、もう1つはEFによるバックエンドです。

お役に立てれば。

于 2011-07-19T03:41:31.517 に答える
2

ただし...MVC/ EFの目的を理解している場合、モデル内にそのビジネスロジックを含めることです...

そして、あなたはどのようなモデルを意味しますか?ASP.NET MVCとEFを使用すると、モデルと呼ばれることもある3つの領域で終了します。

  • EFモデル-データベースへのマッピングを備えたクラスのセットです
  • Model-View-Controller-ここでのモデルとは、ビュー用のデータを準備するためにコントローラーによって消費される何か(通常はビジネスロジック)を意味します
  • ビューモデル-ASP.NETMVCビューモデルは、コントローラーとビューの間でデータが交換されるクラスです。

あなたのクラスを見ると、1番目と3番目のモデルが結合されていることがわかります(ほとんどの場合、これは悪い習慣と見なされます)。あなたの理解は正しいですが、ほとんどの場合、クラスで表されていない2番目のモデルに関してです。すべての「ビジネスロジック」をマッピングで表すことができるわけではありません。さらに、ビジネスロジックを実行するのはデータレイヤーのポイントではありません。

マッピングは部分的に機能しますが(タグタイプは1つの事業会社にのみ関連しています)、それでもデータレイヤーはすべてのビジネスルールを適用しません。データレイヤーを使用すると、Webサイトで異なる事業会社のタグタイプのタグを割り当てることができます。ビジネスロジックでは、これが発生しないようにする必要があります。データベースでこれを回避するには、おそらく複雑な主キーが必要になり、すべての依存オブジェクトに運営会社IDを渡す必要があるため、複雑になります。

于 2011-07-17T09:55:40.667 に答える
0

私があなたなら、データベースでそのような制約を行う代わりに、ビジネスレイヤーを使用してTagtypeをフィルタリングします。私にとって、そのアプローチはもっと簡単かもしれません。

于 2011-07-15T18:28:48.943 に答える