If public UsersContext() is the constructor of the DbContext, why is it inheriting from the OfficeData database? How does the inheritance work? Since a database cannot be a base class.
It's not even a class.
I can understand that the UsersContext is inheriting from the built-in DbContext base class.
public class UsersContext : DbContext
{
public UsersContext(): base("OfficeData")
{
}
//contains this model
public DbSet<UserProfile> UserProfiles { get; set; }
}
It's definitely not "inheriting" anything from "OfficeData". And "OfficeData" isn't a database, it's a string. That's it. In this context, it's a string telling the base class constructor which connection string in the Web/App.config to use when it connects to the database. It has nothing to do with inheritance.
That is name of connection string in config file.
Related
The scenario:
I have a couple websites that I'm rebuilding with Blazor, all do e-commerce. What I want to do is extract the accounting logic (i.e. Orders, OrderItems, Accounts, Transactions, etc) and data operations into an
"Accounting" DLL so I don't have to repeat the code.
I've got the above Entities defined in the DLL, then in the WebApp.Server's DbContext I have the appropriate DbSets.
In the "Accounting" DLL, I have an interface:
public interface IDbAccountringService
{
DbSet<Account> Accounts { get; set; }
//etc
}
which the DbContext in WebApp.Server implements:
public class Db : ApiAuthorizationDbContext<User>, IDbAccountringService
{
public Db(
DbContextOptions options,
IOptions<OperationalStoreOptions> operationalStoreOptions) : base(options, operationalStoreOptions)
{
}
public DbSet<Account> Accounts { get; set; }
}
Then in the "Accounting" DLL, I have the following generic class:
public class DbAccountingService<T> where T : DbContext, IDbAccountringService
{
DbContext dbContext { get; set; }
public DbAccountingService(DbContext T)
{
dbContext = T;
}
public Account[] GetAccounts()
{
//The compiler doesn't see Accounts
return dbContext.Accounts.ToArray();
//It also doesn't see Accounts on itself
return this.Accounts.ToArray();
// However, it does see all the DbContext methods
dbContext.SaveChanges();
}
}
which I instantiate and use in my controller:
[Route("accounting/accounts")]
[ApiController]
public class JournalController : BaseApiController
{
DbAccountingService<Db> _dbAccountingService;
public JournalController(Db db, MtGlobals mtGlobals) : base(mtGlobals)
{
_dbAccountingService = new DbAccountingService<Db>(db);
}
[HttpGet("get-accounts")]
public Account[] GetAccounts()
{
return _dbAccountingService.GetAccounts();
}
}
As the comments in DbAccountingService<T> indicate, the compiler recognizes that dbContext is in fact a DbContext, but it doesn't recognize that it also implements IDbAccountringService.
I'm a little fuzzy on generics, though I usually get them working, however, here, no luck.
Is what I'm trying to do possible? I want to extract all the data operations into the "Accounting" DLL so that I don't have to write duplicate code for each website.
Your dbContext field is of type DbContext:
DbContext dbContext { get; set; }
public DbAccountingService(DbContext T)
{
dbContext = T;
}
Be aware, that you constructor parameter is of type DbContext too with parameter name T. So this T has nothing to do with the generic type parameter, it's just a parameter name.
You want the dbContext property to be the generic type:
T dbContext { get; set; }
public DbAccountingService(T context)
{
dbContext = context;
}
The relevant par is, that your field has type T (because your where constraints this to implement interface IAccountingService.
I'm beginner to .NET but I'm fairly familiar with building webapplications using 3 tier architecture. I usually have a webapplication project for the webforms and a wpf application project to keep my Domain, Controller and Data Access Layer classes.
I'm familiar with creating a DbContext class and using it to deal with the database through EF. I've added .NET Identity to my webapplication project but I need to make changes to the identity user and add more data to it.
I'm following this tutorial to accomplish this but it is intended for MVC. I have 2 seperate context files at the moment, one for identity and other for my usual purposes. is there a way I can have one context?
my DbContext looks like,
namespace ExammerCore.Infrastructure
{
class ExammerContext : DbContext
{
public ExammerContext()
: base("DefaultConnection")
{
}
}
}
the identity DbContext I made using the tutorial looks like,
namespace ExammerCore.Infrastructure
{
class IdentityContext : IdentityDbContext<ApplicationUser>
{
public IdentityContext()
: base("DefaultConnection")
{
}
}
}
My IdentityModels.cs looks like,
namespace ExammerCore.Domain
{
public class ApplicationUser : IdentityUser
{
//You can extend this class by adding additional fields like Birthday
public string BirthDate { get; set; }
}
}
how can I blend these two together to have one DbContext class? or is there another way to add custom fields to a user without inheriting Identity classes?
My solution structure looks like this,
Solution structure
I've googled a lot haven't found an answer.
Change the line
class ExammerContext : DbContext
to
class ExammerContext : IdentityDbContext<ApplicationUser>
to pull all the Identity DbSets into your ExammerContext
in your dbcontext you should have properties that represent what entities get used to build tables.... that should look something like this...
class ExammerContext : DbContext
{
public IDbSet<ApplicationUser> ApplicationUsers { get; set; }
// add other classes/tables here.
public ExammerContext()
: base("DefaultConnection")
{
}
}
this way you will only need your context.
I am programming a few projects which have some core functionality which are similar and then their own functionality outside of that.
I was considering making a class library, using Entity Framework with Code First in order to provide some shared functionality and the database tables that go with it.
For example, I may want to use the class library to send an email and then use entity framework to log in a database table that an email is sent.
This class library would be added into another project, which also uses entity framework - in the same database. So now I would like the database to "build itself", creating the email logging table and some other functionality, e.g. products of some sort.
I have not used Entity Framework before, will having two dlls end up causing any kind of confusion because they're both pointing to the same database but expect different tables? e.g. would they be inclined to delete tables because they don't appear in the code?
Will it also cause problems if I end up over-lapping, e.g. if I want to do a join on all products (Project Entity Framework) which have had an email (Class Library Entity Framework) sent out, would I be able to do a join via linq?
You'll want to keep everything in one DbContext. You can do this by using interfaces to group the entities in each dll, then declare a concrete DbContext class that combines them all in your top-level code.
Project1:
public interface IMyProj1DbContext : IDbContext
{
DbSet<Person> People { get; set; }
DbSet<Place> Places { get; set; }
}
Project2:
public interface IMyProj2DbContext : IDbContext
{
DbSet<Customer> Customers { get; set; }
DbSet<Order> Orders { get; set; }
}
And you'll need a third project that defines the common members:
public interface IDbContext
{
int SaveChanges();
}
Now in the code where all these come together, you can declare a single DbContext class that inmplements all of the interfaces:
public class MyDbContext : DbContext, IMyProj1DbContext, IMyProj2DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<Place> Places { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<Order> Orders { get; set; }
}
Now, you will want to write the code that uses the two different contexts and that code will live inside the individual dlls for each context. But how can you do that?
public class PersonFinder
{
public Person FindPersonByLocation(Place placeToSearch)
{
using (var db = new ???)
{
return db.People.SingleOrDefault(p => p.Location_Id == placeToSearch.Id);
}
}
}
You can't reference the concrete DbContext here because that will cause a circular dependency. The key is to inject the DbContext object at run-time:
public class PersonFinder : Disposable
{
IMyProj1DbContext _db;
public PersonFinder(IMyProj1DbContext db)
{
_db = db;
}
public Person FindPersonByLocation(Place placeToSearch)
{
return _db.People.SingleOrDefault(p => p.Location_Id == placeToSearch.Id);
}
public void Dispose()
{
// ... Proper dispose pattern implementation excluded for brevity
if (_db != null && _db is Disposable)
((Disposable)_db).Dispose();
}
}
*This is not the best way to inject a disposable object, by the way. But it is relatively safe to do it this way and it demonstrates the principle without the extra clutter.
Now you only have one DbContext and EF will generate and maintain one single database, even though you have nice logical domain silos that can operate independently.
When you want to perform a join between the silo entities you code can use the MyDbContext class directly.
I am not sure if this is possible. I have several particular tables in my database represented by entity framework's code first classes. These classes have different properties except in terms of the Id property which is always a string. I am wondering if there is anyway to create a generic repository that can select and render a sequence of just the Id property. For example something like:
class GetDbIds<T> where T : class
{
// PROPERTIES
DbContext DbContext {get;set;}
DbSet<T> DbSet {get;set;}
// CONSTRUCTOR
public GetDbIds(DbContext dbContext)
{
DbContext = dbContext;
DbSet = DbContext.Set<T>();
}
// METHODS
public IEnumerable<string> GenerateNewIdSequence()
{
return DbSet.Select(x => x.Id);
}
}
I know how to set up a basic generic repository, but I haven't came across any patterns that also let you dynamically query the repository as well.
You can constrain T to an interface that has the property:
interface IIdentifiable { string Id { get; } }
class GetDbIds<T> where T : IIdentifiable, class
In many projects I have to make a table containing users and implementing standard user-based functions such as authentication, saving, etc. So I decided to make a class library containing these functionalities, for example:
public class User
{
public int? Id {get;set;}
public string UserName {get;set;}
public string Password {get;set;}
}
public class MyDbContext : DbContext
{
public DbSet<User> {get;set;}
}
public class UserService
{
public MyDbContext Context {get;set;} // will be initialized in constructor
public User GetByUserName(string username)
{
return (from s in Context.Users where s.UserName.Equals(username) select s).SingleOrDefault();
}
// etc...
}
Now when I start a new Mvc project I add this library and extends the DbContext with custom models. The problem is I don't know how to extend the User table with some additional fields, for example:
public class MyUser : User
{
public bool IsApproved {get;set;}
}
public class CustomDbContext : MyDbContext
{
public DbSet<SomeOtherModel> {get;set;}
// problem: override DbSet in MyDbContext with class MyUser?
//public DbSet<MyUser> {get;set;}
}
In this case I also need to override the DbSet<User> of the MyDbContext. If I remove the DbSet<User> in the library my UserService class won't work anymore. Any ideas how to make an extensible framework?
You could use generics (I haven't tested this, just a thought):
public abstract class UserDbContext<TUser> : DbContext where TUser : User
{
public DbSet<TUser> Users {get;set;}
}
And then inherit:
public class CustomDbContext : MyDbContext<MyUser>
And the same generic in the UserService:
public abstract class UserService<TUser> where TUser : User
{
public UserDbContext<TUser> Context {get;set;} // will be initialized in constructor
public TUser GetByUserName(string username)
{
return (from s in Context.Users where s.UserName.Equals(username) select s).SingleOrDefault();
}
// etc...
}
Don't inherit from User, instead make User a partial class and extend User that way. That only works if your library is just a set of source files, and not compiled into an assembly.
EDIT:
Another option is to simply not define the dbcontext in your framework, and define it using your library classes in your application project. You could then call an initialization function in your framework to do the mappings you need and call it from OnModelCreating.
You could always use composition and have MyUser contain a User property. Then, you would have a brand-new DbContext that would have a DbSet.
This would create two tables in the database, but is probably the easiest. (disclaimer: haven't tried this and you may encounter cross-assembly issues)