2

I just wondering if you can store a function in a model (CRUD transactions) that will look something like this:

My Existing code:

public class tbluser
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int id { get; set; }

    [Required(ErrorMessage = "Username is required")]
    public string username { get; set; }

    [Required(ErrorMessage = "Password is required")]
    public string password { get; set; }

    public static List<tbluser> list()
    {
        using (var db = new sample())
        {
            var user = db.tbluser.ToList();
            return user;
        }
    }
}

What i want:

public class tbluser:DbContext
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int id { get; set; }

    [Required(ErrorMessage = "Username is required")]
    public string username { get; set; }

    [Required(ErrorMessage = "Password is required")]
    public string password { get; set; }


    public static List<tbluser> list()
    {
        return this.toList();
    }
}

I just want to ask also if that method of implementing Entity Framework is ok.

3
  • 4
    You could, but it is more common to not couple the logic from your context so tightly to your models. It is easier to test with your models and context separate. Also, it is usually better design to separate your concerns. Commented Jun 12, 2018 at 3:55
  • 1
    Completely agree with @JasonW. Arianne - you should not mix the model with DataContext. Also to have segregation of concern, you can use the Repository pattern or other. check this - c-sharpcorner.com/UploadFile/b1df45/… Commented Jun 12, 2018 at 4:35
  • Just for demonstration purposes: do some performance and memory profiling when the second list method produces a couple of thousands of user objects. It's good to think out of the box, but most of the times the conclusion is that the box makes sense. Commented Jun 12, 2018 at 6:34

3 Answers 3

1

Here is a quick example of how you might setup a simple Code First implementation to get started.

First, define your User model. The Key attribute on an integer type automatically configures the identity property for you. Then, you may want an index on username if you plan to do frequent lookups by username (to get user details or to validate a password).

public class User
{
    [Key] // Becomes identity by default
    public int Id { get; set; }
    [Index("IX_User_Username", IsUnique = true)]
    public string Username { get; set; }
    public string Password { get; set; }
}

Then, you can define

public class AppDataContext : DbContext
{
    public AppDataContext() : base("name=DBConnection") { }
    public DbSet<User> Users { get; set; }
}

You will just need to be sure there is a connection string in your config file to match the name passed there.

<connectionStrings>
    <add name="DBConnection"  providerName="System.Data.SqlClient"
        connectionString="Data Source=instancePath;Initial Catalog=dbName;Integrated Security=true;MultipleActiveResultSets=True" />
</connectionStrings>

This would now allow you to create repos such as this:

public class UserRepo : IDisposable
{
    public Lazy<AppDataContext> _db = new Lazy<AppDataContext>(() => new AppDataContext());

    public IQueryable<User> Get() => _db.Value.Users.AsQueryable();
    public IList<User> GetAll() => _db.Value.Users.ToList();

    public void Dispose()
    {
        if (_db.IsValueCreated)
            _db.Value.Dispose();
    }
}

So then you can either use the repo or the context directly.

// Use the repo
using (var userRepo = new UserRepo())
{
    var allUsers = userRepo.GetAll();
    var user = userRepo.Get().FirstOrDefault(m => m.Username == "myUsername");
}
// Or just use the data context
using (var db = new AppDataContext())
{
    var allUsers = db.Users.ToList(); // Get all users
    var user = db.Users.FirstOrDefault(m => m.Username == "myUsername");
}

For more information, here are some useful links with great details:

Sign up to request clarification or add additional context in comments.

Comments

1

Code like this is going to be heavily problematic.

In the first example you are tightly coupling an instance of a DbContext to an entity. Calling tblUser.list() will return a list of User entities, but these will now be outside of the scope of a DbContext. (Due to the using() block closure) This means that any lazy load calls to retrieve related entities will fail and you cannot persist any changes to the entities until they are re-attached to another DbContext. This gets very messy, very fast.

In the second example you would be extending a DbContext, meaning each "entity" is effectively scoping a DbContext use to populate instances of itself. You can't just "static" wrap the method because that wouldn't have visibility to the non-static DbSets inherited from DbContext.

This would be horrible in terms of performance, and from a code perspective would look plain weird:

I.e.

using (var user = new tbluser)
{
   var users = user.list(); // not static.
   // .. Do stuff..
}

To make it static would be problematic because a DbContext would need to be static-scoped inside tbluser

public class tbluser
{
   private static MyContext _context = new MyContext();

   // ...

   public static List<tbluser> list()
   {
      return _context.tblusers.ToList();
   }
}

And this may still have issues, such as how the static instance is disposed, before it was remotely functional but I certainly cannot recommend an approach like this.

Instead, use the DbContext as it is intended. Look at IoC containers like Unity or Autofac to manage the lifetime scope for for the DbContext and inject an instance as a dependency into classes that need it, or at a minimum wrap it in a using() {} block and treat it like an repository with it's DbSets.

There are lots of examples of using the DbContext effectively, using Repositories and Unit of Work patterns with dependency injection. Master these before attempting to spin up something unique. Future developers looking at your code will thank you. :)

1 Comment

Thanks for the advice :) ..i realize that my code is surely is a mess right now..i want to dig deeper in this...thanks guys :)
1

There is one famous principle called "Separation of Concerns" that will get very angry if you do this. My advice is to keep the code simple, meaningful and loosely coupled.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.