C#中的类和方法,这是一个好的方法吗?

3

我正在尝试构建一个与我的asp.net web应用程序中的数据库交互的类。我需要您的意见,关于如何设计它,这里是我考虑的一个示例:

public class Person
{
    int personId;
    string name;
    string lastName;

    public int PersonId
    {
        get { return personId; }
    }

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    public string LastName
    {
        get { return lastName; }
        set { lastName = value; }
    }

    public Person()
    {

    }

    public static void Save(Person p)
    {
        //datalayer here
        //save the person class
    }

    public static Person GetPerson(int person_id)
    {
        //datalayer here
        //get the person from database and return a person class
        Person p = new Person();
        p.personId = 10;
        p.name = "Alex";
        return p;
    }
}

这样我就不需要实例化类就可以使用数据库方法:

Person p = Person.GetPerson(19);
p.Name = "Alex...";
Person.Save(p);

感谢您的帮助。


1
你需要的是对象的工厂方法模式,以及数据访问代码的仓储模式 - Esoteric Screen Name
4个回答

4

请使用Automatic属性,因为您的私有字段在代码中具有相同的功能。

我认为Save是可以在Person实体对象上执行的操作。因此,我不会将其作为静态方法保存。我会将您的Save代码移动到Person对象的方法中,以便我可以像这样调用它:obj.Save()。为了加载数据,我将使用我的类constructor的重载版本。

public class Person
{
    int personId;      

    public int PersonId
    {
        get { return personId; }
    }    
    public string Name { set;get;}   
    public string LastName { set;get;}        

    public Person() {}

    public Person(int person_id)
    {
        //call to datalayer here
        //get the person from database and return a person class          
        personId = 10;
        Name= "Alex";  // set the public property value here           
    }
    public bool Save()
    {
        //datalayer here
        //save the person class and return
      // true/false /or new ID (change return type)
    }    

}

当调用时,

Person p = new Person(19);  //get existing person
p.Name = "New Name";
p.Save();

编辑:另一种(更好的)方法是将实体类保持为简单的POCO。这意味着不要在那里添加数据访问/ BL代码。它将简单地像这样:

public class Person
{
  public int ID { set;get;}
  public string Name { set;get;}
}

有一个Repository可以为您执行数据操作。因此,您的存储库可能会有以下方法

public interface IRepository
{ 
   Person GetPerson(int id);
   bool SavePerson(Person person);
}

你可以在一个类中实现这个接口来执行你的数据访问操作。
public class Repository:IRepository
{
  //implementation of your DA methods here
}

现在你可以像这样从不同层(业务层)调用它。
IRepository repo = new Repository();

var person=repo.GetPerson(19);  
person.Name="Updated Name";
repo.Save(person);

谢谢你的提示;不知怎么回事,我忘记了自动属性! - Alex
-1:将持久层靠近UI并不是仓储模式的正确使用方式。 - Esoteric Screen Name
@EsotericScreenName,你能解释一下“靠近用户界面”是什么意思吗? - Shyju
1
我将实体(POCO)和数据访问层作为独立的项目,以便在需要时可以在不同的项目中使用相同的实体。 - Shyju
这实际上是最好的方法(仓储模式)在它自己的类库中,然后从asp.net web应用程序中,当实例化仓储时,我可以发送仓储将使用的连接字符串。不确定是否公平将其标记为正确答案,但对于我正在考虑的事情来说,这肯定是最好的。 - Alex
显示剩余4条评论

1
你需要的是对象的工厂方法模式和数据访问代码的仓储模式。我无法像文章那样解释得那么好,所以我将概述基本思想并提供一些示例。
目标是将代码库分成处理特定类型问题的层,例如与用户通信(UI),在应用程序中保存和验证数据(业务类/模型)或管理数据持久性(数据访问)。保持这些区域整洁分明使维护和调试代码或并行开发更容易。还有其他好处,例如促进跨多个物理机器的架构,但这超出了问题的范围。
基本结构:
获取概念进展:
UI -> Person Factory -> Person class -> Repository -> Database

保存概念进展:

UI -> Person class -> Repository -> Database

Person类结构,内部有解释性注释:

public class Person
{
   // various properties & methods

   // Constructor access is restricted to control how the class gets consumed.
   // All instance management must go through the factories.
   protected Person() { /* stuff */ }

   // Person factory implementation. It's done inside the Person class so that
   // tight control can be kept over constructor access.
   // The factory is what gives you your instances of Person.
   // It has defined inputs and outputs, as well as more descriptive
   // names than constructor overloads, so consumers know what to expect.
   // It's also a place to put scaffolding code, so you can avoid doing 
   // things like setting properties every time you fetch an instance.
   // The factory takes care of all the object initialization and returns
   // an instance that's ready for use.
   public static Person GetPerson(int id)
   {
       Person p = new Person();

       // here you call the repository. It should return either a native
       // data structure like DataReader or DataTable, or a simple DTO class
       // which is then used to populate the properties of Person.
       // the reason for this is to avoid a circular dependency between
       // the repository and Person classes, which will be a compile time error
       // if they're defined in separate libraries
       using(PersonRepository repo = new PersonRepository())
       {
          DataReader dr = repo.GetPerson(id);
          p.FillFromDataReader(dr);
       }

       return p;
   }

   protected void FillFromDataReader(DataReader dr)
   { /* populate properties in here */ }

   // Save should be an instance method, because you need an instance of person
   // in order to save. You don't call the dealership to drive your car,
   // only when you're getting a new one, so the factory doesn't do the saving.
   public void Save()
   {
      // Again, we call the repository here. You can pass a DTO class, or
      // simply pass the necessary properties as parameters
      using(PersonRepository repo = new PersonRepository())
      {
         this.Id = repo.SavePerson(name, address);
      }
   }
}

现在,代码库:

// This class implements IDisposable for easy control over DB connection resources.
// You could also design and implement an IRepository interface depending on your needs.
public class PersonRepository : IDisposable
{
   private SqlConnection conn;

   public PersonRepository()
   {
      // in here you initialize connection resources
      conn = new SqlConnection("someConnectionString");
   }

   public void IDisposable.Dispose()
   {
      // clean up the connection
      conn.Dispose();
   }

   // The instance methods talk to the database
   public int SavePerson(string name, string address)
   {
      // call your stored procedure (or whatever) and return the new ID
      using(SqlCommand cmd = conn.CreateCommand())
      {
         // stuff
         return (int)cmd.Parameters["myOutputIDParameter"].Value;
      }
   }

   public DataReader GetPerson(int id)
   {
      // call your stored procedure (or whatever) and return the fetched data
      using(SqlCommand cmd = conn.CreateCommand())
      {
         // stuff
         return cmd.ExecuteReader();
      }
   }
}

最后,在用户界面层面上,您需要执行以下操作:

Person joe = Person.GetPerson(joeId);
// stuff
joe.Save();

1

我喜欢持久性无知这一概念:持久性无知有哪些优点?)

如果这样的话,你应该将保存方法移动到另一个类中,以便实体不包含任何信息,即如何进行持久化。


-1

你做得对,但是你也可以为你的类使用自动属性。这样可能会节省一些时间。 例如:

public class Person
{

    public int PersonId { get; set;}    
    public string Name { get; set;}
    public string LastName { get; set;}

    public Person()
    {
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接