ASP.NET MVC2 - использование сгенерированного LINQ класса (проблема проверки) - PullRequest
1 голос
/ 03 мая 2010

В ASP.NET MV2 мне мало что не понятно. В базе данных у меня есть таблица Contacts с несколькими полями, и есть дополнительное поле XmlFields того типа xml. В этом поле хранятся дополнительные поля описания.
Есть 4 класса:

  1. Contact класс, который соответствует таблице Contact и определяется по умолчанию при создании классов LINQ
  2. ContactListView класс, который наследует Contact класс и имеет некоторые дополнительные свойства
  3. ContactXmlView класс, который содержит поля из XmlFields поля
  4. ContactDetailsView класс, который сливается ContactListView и ContactXmlView в один класс и этот используется для отображения данных в просмотр страниц

ContactListView класс переопределил некоторые свойства класса Contact (чтобы я мог добавить фильтр [Required], используемый для проверки) - но я получаю предупреждение:

'ObjectTest.Models.Contacts.ContactListView.FirstName' скрывает унаследованный член 'SA.Model.Contact.FirstName. Использовать новое ключевое слово, если целью было скрытие.

ContactDetailsView класс также используется в форме при создании нового контакта и добавлении его в базу данных.

Я не уверен, что это правильный путь, и предупреждающее сообщение немного смущает меня. Любой совет по этому поводу?

Спасибо
Ile

EDIT

Согласно инструкциям Якоба Я пробовал с нуля:

[MetadataType(typeof(Person_Validation))]
    public partial class Person
    {
    }

    public class Person_Validation 
    {
        [Required]
        string FirstName { get; set; }

        [Required]
        string LastName { get; set; }

        [Required]
        int Age { get; set; }
    }

В контроллере у меня есть это:

[HttpPost]
        public ActionResult Create(Person person, FormCollection collection)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    personRepository.Add(person);
                    personRepository.Save();
                }
                catch
                {
                    return View(person);
                }
            }

            return RedirectToAction("Index");            
        }

Вид:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Validate.Models.Person>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
 Create
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Create</h2>

    <% using (Html.BeginForm()) {%>
        <%= Html.ValidationSummary(true) %>

        <fieldset>
            <legend>Fields</legend>           

            <div class="editor-label">
                <%= Html.LabelFor(model => model.FirstName) %>
            </div>
            <div class="editor-field">
                <%= Html.TextBoxFor(model => model.FirstName) %>
                <%= Html.ValidationMessageFor(model => model.FirstName) %>
            </div>

            <div class="editor-label">
                <%= Html.LabelFor(model => model.LastName) %>
            </div>
            <div class="editor-field">
                <%= Html.TextBoxFor(model => model.LastName) %>
                <%= Html.ValidationMessageFor(model => model.LastName) %>
            </div>

            <div class="editor-label">
                <%= Html.LabelFor(model => model.Age) %>
            </div>
            <div class="editor-field">
                <%= Html.TextBoxFor(model => model.Age) %>
                <%= Html.ValidationMessageFor(model => model.Age) %>
            </div>

            <p>
                <input type="submit" value="Create" />
            </p>
        </fieldset>

    <% } %>

    <div>
        <%= Html.ActionLink("Back to List", "Index") %>
    </div>

</asp:Content>

При публикации нового человека без значений ничего не происходит (страница просто перезагружается). При публикации с некоторыми значениями, человек добавляется в БД. Понятия не имею, что я делаю не так.

РЕДАКТИРОВАТЬ 2

Я думаю, что проблема в LINQ, который уже сгенерировал частичный класс Person. Когда я определяю новый частичный класс Person и нажимаю на него и "Перейти к определению", я получаю следующие предупреждения:

C: \ Документы и настройки \ Korisnik \ My Документы \ Visual Studio 2008 \ Projects \ Validate \ Validate \ Models \ DataClasses1.designer.cs - (78, 23): Validate.Models.Person

C: \ Документы и настройки \ Korisnik \ My Документы \ Visual Studio 2008 \ Projects \ Validate \ Validate \ Models \ PersonRepository.cs - (11, 26): Validate.Models.Person

И это часть класса, сгенерированного LINQ:

[Table(Name="dbo.Persons")]
 public partial class Person : INotifyPropertyChanging, INotifyPropertyChanged
 {

  private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);

  private int _PersonID;

  private string _FirstName;

  private string _LastName;

  private string _Age;

                ...

Я почти уверен, что это причина, но я не знаю, как это решить. Есть идеи?

РЕДАКТИРОВАТЬ 3
Хорошо, давайте начнем ... Итак, это структура папок:

http://img535.imageshack.us/img535/3187/70090809.gif http://img227.imageshack.us/img227/6643/15910591.gif

Dataclasses1.designer.cs:

#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:2.0.50727.3603
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace Validate.Models
{
 using System.Data.Linq;
 using System.Data.Linq.Mapping;
 using System.Data;
 using System.Collections.Generic;
 using System.Reflection;
 using System.Linq;
 using System.Linq.Expressions;
 using System.ComponentModel;
 using System;


 [System.Data.Linq.Mapping.DatabaseAttribute(Name="Database1")]
 public partial class DataClasses1DataContext : System.Data.Linq.DataContext
 {

  private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource();

    #region Extensibility Method Definitions
    partial void OnCreated();
    partial void InsertPerson(Person instance);
    partial void UpdatePerson(Person instance);
    partial void DeletePerson(Person instance);
    #endregion

  public DataClasses1DataContext() : 
    base(global::System.Configuration.ConfigurationManager.ConnectionStrings["Database1ConnectionString"].ConnectionString, mappingSource)
  {
   OnCreated();
  }

  public DataClasses1DataContext(string connection) : 
    base(connection, mappingSource)
  {
   OnCreated();
  }

  public DataClasses1DataContext(System.Data.IDbConnection connection) : 
    base(connection, mappingSource)
  {
   OnCreated();
  }

  public DataClasses1DataContext(string connection, System.Data.Linq.Mapping.MappingSource mappingSource) : 
    base(connection, mappingSource)
  {
   OnCreated();
  }

  public DataClasses1DataContext(System.Data.IDbConnection connection, System.Data.Linq.Mapping.MappingSource mappingSource) : 
    base(connection, mappingSource)
  {
   OnCreated();
  }

  public System.Data.Linq.Table<Person> Persons
  {
   get
   {
    return this.GetTable<Person>();
   }
  }
 }

 [Table(Name="dbo.Persons")]
 public partial class Person : INotifyPropertyChanging, INotifyPropertyChanged
 {

  private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);

  private int _PersonID;

  private string _FirstName;

  private string _LastName;

  private string _Age;

    #region Extensibility Method Definitions
    partial void OnLoaded();
    partial void OnValidate(System.Data.Linq.ChangeAction action);
    partial void OnCreated();
    partial void OnPersonIDChanging(int value);
    partial void OnPersonIDChanged();
    partial void OnFirstNameChanging(string value);
    partial void OnFirstNameChanged();
    partial void OnLastNameChanging(string value);
    partial void OnLastNameChanged();
    partial void OnAgeChanging(string value);
    partial void OnAgeChanged();
    #endregion

  public Person()
  {
   OnCreated();
  }

  [Column(Storage="_PersonID", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
  public int PersonID
  {
   get
   {
    return this._PersonID;
   }
   set
   {
    if ((this._PersonID != value))
    {
     this.OnPersonIDChanging(value);
     this.SendPropertyChanging();
     this._PersonID = value;
     this.SendPropertyChanged("PersonID");
     this.OnPersonIDChanged();
    }
   }
  }

  [Column(Storage="_FirstName", DbType="NChar(10)")]
  public string FirstName
  {
   get
   {
    return this._FirstName;
   }
   set
   {
    if ((this._FirstName != value))
    {
     this.OnFirstNameChanging(value);
     this.SendPropertyChanging();
     this._FirstName = value;
     this.SendPropertyChanged("FirstName");
     this.OnFirstNameChanged();
    }
   }
  }

  [Column(Storage="_LastName", DbType="NChar(10)")]
  public string LastName
  {
   get
   {
    return this._LastName;
   }
   set
   {
    if ((this._LastName != value))
    {
     this.OnLastNameChanging(value);
     this.SendPropertyChanging();
     this._LastName = value;
     this.SendPropertyChanged("LastName");
     this.OnLastNameChanged();
    }
   }
  }

  [Column(Storage="_Age", DbType="NChar(10)")]
  public string Age
  {
   get
   {
    return this._Age;
   }
   set
   {
    if ((this._Age != value))
    {
     this.OnAgeChanging(value);
     this.SendPropertyChanging();
     this._Age = value;
     this.SendPropertyChanged("Age");
     this.OnAgeChanged();
    }
   }
  }

  public event PropertyChangingEventHandler PropertyChanging;

  public event PropertyChangedEventHandler PropertyChanged;

  protected virtual void SendPropertyChanging()
  {
   if ((this.PropertyChanging != null))
   {
    this.PropertyChanging(this, emptyChangingEventArgs);
   }
  }

  protected virtual void SendPropertyChanged(String propertyName)
  {
   if ((this.PropertyChanged != null))
   {
    this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
   }
  }
 }
}
#pragma warning restore 1591

PersonRepository.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using Validate.Models;

namespace Validate.Models
{
    [MetadataType(typeof(Person_Validation))]
    public partial class Person
    {
    }

    public class Person_Validation 
    {
        [Required]
        string FirstName { get; set; }

        [Required]
        string LastName { get; set; }

        [Required]
        int Age { get; set; }
    }

    public class PersonRepository
    {
        private DataClasses1DataContext db = new DataClasses1DataContext();

        public IQueryable<Person> FindAllPersons()
        {
            return db.Persons;
        }

        public Person GetPerson(int id)
        {
            return db.Persons.SingleOrDefault(x => x.PersonID == id);
        }

        public void Add(Person person)
        {
            db.Persons.InsertOnSubmit(person);
        }

        public void Delete(Person person)
        {
            db.Persons.DeleteOnSubmit(person);
        }

        public void Save()
        {
            db.SubmitChanges();
        }
    }
}

/ Views / Person / Create.aspx:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Validate.Models.Person>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
 Create
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Create</h2>

    <%= ViewData["greska"]%>

    <% using (Html.BeginForm()) {%>
        <%= Html.ValidationSummary(true) %>

        <fieldset>
            <legend>Fields</legend>           

            <div class="editor-label">
                <%= Html.LabelFor(model => model.FirstName) %>
            </div>
            <div class="editor-field">
                <%= Html.TextBoxFor(model => model.FirstName) %>
                <%= Html.ValidationMessageFor(model => model.FirstName) %>
            </div>

            <div class="editor-label">
                <%= Html.LabelFor(model => model.LastName) %>
            </div>
            <div class="editor-field">
                <%= Html.TextBoxFor(model => model.LastName) %>
                <%= Html.ValidationMessageFor(model => model.LastName) %>
            </div>

            <div class="editor-label">
                <%= Html.LabelFor(model => model.Age) %>
            </div>
            <div class="editor-field">
                <%= Html.TextBoxFor(model => model.Age) %>
                <%= Html.ValidationMessageFor(model => model.Age) %>
            </div>

            <p>
                <input type="submit" value="Create" />
            </p>
        </fieldset>

    <% } %>

    <div>
        <%= Html.ActionLink("Back to List", "Index") %>
    </div>

</asp:Content>

Ответы [ 2 ]

5 голосов
/ 03 мая 2010

Один из способов сделать это - использовать MetadataTypeAttribute. Этот атрибут позволяет вам связать класс «приятеля» с вашим классом LINQ2SQL. Класс собеседника содержит те же свойства, что и исходный класс, но ASP.NET MVC будет считывать атрибуты проверки из класса собеседника. MetadataTypeAttribute был введен, потому что C # не позволяет вам добавлять атрибуты, определенные в базовом классе - следовательно, вы получаете ошибку.

Следующий пример скопирован из MSDN :

[MetadataType(typeof(CustomerMetaData))]
public partial class Customer
{
}

public class CustomerMetaData
{
    // Apply RequiredAttribute
    [Required(ErrorMessage = "Title is required.")]
    public object Title { get; set; }
}

EDIT:

Я не уверен, что ваше действие правильно выполнено. Когда состояние вашей модели недопустимо, вы хотите снова показать представление «Создать». Попробуйте что-то вроде этого:

[HttpPost]
public ActionResult Create(Person person, FormCollection collection)
{
    if (ModelState.IsValid)
    {
        try
        {
            personRepository.Add(person);
            personRepository.Save();
            return RedirectToAction("Index");            
        }
        catch
        {
            return View(person);
        }
    }
    else
        return View(person);     
}

РЕДАКТИРОВАТЬ 2:

Linq2Sql уже создал частичный класс Person для вас, и так и должно быть. Когда вы создаете свой собственный частичный класс Person, компилятор объединит определение вашего класса с определением класса, созданным Linq2Sql, в один класс Person. Но чрезвычайно важно, чтобы два частичных определения классов были в одной сборке и в одном и том же пространстве имен . Поэтому убедитесь, что вы поместили частичное определение класса Person в то же пространство имен, что и класс Person Linq2Sql.


РЕДАКТИРОВАТЬ 3:

Мне вдруг пришло в голову, что свойства вашего Person_Validation класса являются частными. Они должны быть публичными. Надеюсь, это поможет: -)

2 голосов
/ 03 мая 2010

@ Jakob показывает правильный способ сделать это, если вы хотите использовать ваши классы модели данных непосредственно в ваших представлениях. Вы также можете рассмотреть возможность отделения моделей представлений от моделей данных и добавления аннотаций к моделям представлений. Это не помешает вам использовать валидацию на основе метаданных и в вашей модели данных, но будет дополнительно отделять ваше представление от вашей модели данных. Я часто нахожу, что мне нужно больше (или разные) данных в моем представлении, и вместо того, чтобы поддаться искушению расширить класс модели данных непостоянными данными, я считаю, что использование отдельной модели представления и перевод между ними предпочтительнее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...