简体   繁体   中英

class & method in C#, is this a good approach?

I am trying to build a class that interacts with the database in my asp.net web application. I need your opinion on how to design it, here's an example of what I have in mind

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;
    }
}

So that i can use the database methods without having to instantiate the class:

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

I appreciate your help.

Use Automatic proerties because your private fields does the same in your code.

I think, Save is an Operation which can be done on an object of Person Entity . So i wont keep it as a Static method. I would move your Save code as a method of the Person object. So that i will call it like obj.Save() . To load the data, I would use an overloaded version of my class 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)
    }    

}

And when calling,

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

EDIT : Another (better) approach is to keep your entity classes as simple POCO's. that means no data acccess / BL code there. It will simply look like

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

And have a Repository which does the data operations for you. So your repository may have methods like this

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

You may implement this Interface in a class to do your Data Access operations

public class Repository:IRepository
{
  //implementation of your DA methods here
}

Now you may call it from different layer(business layer) like this

IRepository repo = new Repository();

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

I like the persistance ignorance thing: What are the benefits of Persistence Ignorance? )

In that case you should move the Save method to another class so the entity doesnt contain any information how it should be persisted.

What you're after is the factory method pattern for the objects, and the repository pattern for the data access code. I can't explain it nearly as well as the articles, so instead I'll go over the basic ideas and provide some examples.

The goal is to divide up your code base in to layers that deal with one specific type of concern, such as communicating with the user (UI), holding and validating data within the application (business classes / model), or managing data persistence (data access). Keeping these areas neatly divided makes it easier to maintain and debug code or develop in parallel. There are other benefits as well, such as facilitating architecture across multiple physical machines, but that's outside the scope of the question.

The basic structure:

Fetching conceptual progression:

UI -> Person Factory -> Person class -> Repository -> Database

Saving conceptual progression:

UI -> Person class -> Repository -> Database

Person class structure, with explanatory comments inside:

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);
      }
   }
}

Now, the repository code:

// 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();
      }
   }
}

Finally, here's what you'd do at the UI level:

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

You are doing right but you can also use automatic properties for you class. It may save some of your time. eg.

public class Person
{

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

    public Person()
    {
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM