Подтвердить что ты не робот

ASP.NET MVC 4, EF5, уникальное свойство в модели - лучшая практика?

ASP.NET MVC 4, EF5, Первый код, SQL Server 2012 Express

Какова наилучшая практика для обеспечения уникальной ценности в модели? У меня есть класс мест, у которого есть свойство url, которое должно быть уникальным для каждого места.

public class Place
{
      [ScaffoldColumn(false)]
      public virtual int PlaceID { get; set; }

      [DisplayName("Date Added")]
      public virtual DateTime DateAdded { get; set; }

      [Required(ErrorMessage = "Place Name is required")]
      [StringLength(100)]
      public virtual string Name { get; set; }

      public virtual string URL { get; set; }
};

Почему в нем нет только [уникальной] аннотации данных?

Я видел 1 или 2 обсуждения этого вопроса, но не говорил о лучшей практике. С помощью Code First вы каким-то образом можете указать базе данных установить уникальное ограничение для поля в базе данных?

Что является самым простым способом - и что лучше всего?

4b9b3361

Ответ 1

Как сумасшедший, как может показаться, лучшей практикой в ​​настоящее время является не использовать встроенную проверку и вместо этого использовать FluentValidation. Тогда код будет очень прост в чтении и супер-ремонтопригодной, так как проверка будет управляться в отдельном классе, что означает меньше кода спагетти.

Псевдо пример того, чего вы пытаетесь достичь.

[Validator(typeof(PlaceValidator))]
class Place
{
    public int Id { get; set; }
    public DateTime DateAdded { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }
}

public class PlaceValidator : AbstractValidator<Place>
{
    public PlaceValidator()
    {
        RuleFor(x => x.Name).NotEmpty().WithMessage("Place Name is required").Length(0, 100);
        RuleFor(x => x.Url).Must(BeUniqueUrl).WithMessage("Url already exists");
    }

    private bool BeUniqueUrl(string url)
    {
        return new DataContext().Places.FirstOrDefault(x => x.Url == url) == null
    }
}

Ответ 2

Эта ссылка может помочь:  https://github.com/fatihBulbul/UniqueAttribute

[Table("TestModels")]
public class TestModel
{

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

    [Display(Name = "Some", Description = "desc")]
    [Unique(ErrorMessage = "This already exist !!")]
    public string SomeThing { get; set; }
}

Ответ 3

Единственный способ - обновить миграцию после ее создания, предполагая, что вы используете их, чтобы он принудительно применял уникальное ограничение для столбца.

public override void Up() {
  // create table
  CreateTable("dbo.MyTable", ...;
  Sql("ALTER TABLE MyTable ADD CONSTRAINT U_MyUniqueColumn UNIQUE(MyUniqueColumn)");
}
public override void Down() {
  Sql("ALTER TABLE MyTable DROP CONSTRAINT U_MyUniqueColumn");
}

Жесткий бит, тем не менее, принуждает ограничение на уровне кода до того, как вы попадете в базу данных. Для этого вам может понадобиться репозиторий, который содержит полный список уникальных значений и гарантирует, что новые объекты не будут нарушать это с помощью метода factory.

// Repository for illustration only
public class Repo {
  SortedList<string, Entity1> uniqueKey1 = ...; // assuming a unique string column 
  public Entity1 NewEntity1(string keyValue) {
    if (uniqueKey1.ContainsKey(keyValue) throw new ArgumentException ... ;
    return new Entity1 { MyUniqueKeyValue = keyValue };
  }
}

Литература:

Сноска:

В коде есть много запросов для [Unique], но похоже, что он даже не делает версию 6: http://entityframework.codeplex.com/wikipage?title=Roadmap

Вы можете проголосовать за него здесь: http://data.uservoice.com/forums/72025-entity-framework-feature-suggestions/suggestions/1050579-unique-constraint-i-e-candidate-key-support

Ответ 4

Вы можете выполнить эту проверку на уровне кода перед сохранением данных в таблицах базы данных.

Вы можете попробовать использовать аннотацию данных Remote на вашей модели просмотра, чтобы выполнить асинхронную проверку, чтобы сделать пользовательский интерфейс более отзывчивым.

public class CreatePlaceVM
{
  [Required]
  public string PlaceName { set;get;}

  [Required]
  [Remote("IsExist", "Place", ErrorMessage = "URL exist!")
  public virtual string URL { get; set; }
}

Убедитесь, что у вас есть метод действия IsExists в Placecontroller, который принимает параметр URL и проверяет его снова в вашей таблице и возвращает true или false.

В этой ссылке msdn есть пример программы, показывающей, как реализовать атрибут Remote для мгновенной проверки.

Кроме того, если вы используете хранимую процедуру (По какой-либо причине), вы можете выполнить проверку EXISTS там перед запросом INSERT.

Ответ 5

Я решил общую проблему включения инсталляции конструктора в вашем потоке проверки, интегрируя его в обычный механизм DataAnnotations, не прибегая к фреймворкам в этом ответе, позволяя писать:

class MyModel 
{
    ...
    [Required, StringLength(42)]
    [ValidatorService(typeof(MyDiDependentValidator), ErrorMessage = "It simply unacceptable")]
    public string MyProperty { get; set; }
    ....
}

public class MyDiDependentValidator : Validator<MyModel>
{
    readonly IUnitOfWork _iLoveWrappingStuff;

    public MyDiDependentValidator(IUnitOfWork iLoveWrappingStuff)
    {
        _iLoveWrappingStuff = iLoveWrappingStuff;
    }

    protected override bool IsValid(MyModel instance, object value)
    {
        var attempted = (string)value;
        return _iLoveWrappingStuff.SaysCanHazCheez(instance, attempted);
    }
}

С некоторыми вспомогательными классами (смотрите там), вы подключаете его, например. в ASP.NET MVC, как в Global.asax: -

DataAnnotationsModelValidatorProvider.RegisterAdapterFactory(
    typeof(ValidatorServiceAttribute),
    (metadata, context, attribute) =>
        new DataAnnotationsModelValidatorEx(metadata, context, attribute, true));