I'm using EF4 CTP5 code first approach but am having trouble getting it to work. I have a class called "Company" and a database table called "CompanyTable". I want to map the Company class to the CompanyTable table, so have code like this:
[Table(Name = "CompanyTable")]
public class Company
{
[Key]
[Column(Name = "CompanyIdNumber", DbType = "int")]
public int CompanyNumber { get; set; }
[Column(Name = "CompanyName", DbType = "varchar")]
public string CompanyName { get; set; }
}
I then call it like so:
var db = new Users();
var companies = (from c in db.Companies
select c).ToList();
However it errors out:
Invalid object name 'dbo.Companies'.
It's obviously not respecting the Table attribute on the class, even though it says here that Table attribute is supported. Also it's pluralizing the name it's searching for (Companies instead of Company.) How do I map the class to the table name?
on you class that inherits from DbContext, override the OnModelCreating method
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Company>().ToTable("dbo.CompanyTable");
}
Forgot to add a reference to the ctp5 dll to my schemas project, it was using System.Data.Linq.Mapping instead.
Related
To support tenan/companies, I added/extended a new property to the AspUser Table called OrgId in ASP MVC 5, Identity 2.2 role management, I added the corresponding OrgId to some other tables, looked here but no answers
During User Login() and the UserSession
how do I cache, configure & retrieve the OrgId, so that I can perform DBConext filtering/CRUD of table for Org specific records?
Advice: is better to save this in the Claims, FormsToken or Session - and
how to set the tenanId context in session?
I know how to get user, but not the extended Org
ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(System.Web.HttpContext.Current.User.Identity.GetUserId());
Your customized user class should be like this:
public class CustomizedUser : IdentityUser
{
public int OrgId {get; set;}
public DateTime JoinDate { get; set; }
//...
// and other simple fields
//Fields related to other tables
public virtual ICollection<Article> Articles { get; set; } = new List<Article>();
//...
}
And your CustomizedApplicationDbContext class
public class CustomizedApplicationDbContext : IdentityDbContext<CustomizedUser>, IApplicationDbContext
{
public CustomizedApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static CustomizedApplicationDbContext Create()
{
return new CustomizedApplicationDbContext();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//your entity configurations go here if you have any
base.OnModelCreating(modelBuilder);
}
//These fields are neccessary in order to maintain the power of base class
public DbChangeTracker Changetracker => base.ChangeTracker;
public Database DatabBase => base.Database;
//your own dbsets go here except CustomizedUser, because the base class IdentityDbContext<CustomizedUser> handles it
public IDbSet<Article> Articles { get; set; }
//...
}
Now, Remember to replace every ApplicationDbContext references with CustomizedApplicationDbContext and every IdentityUser refrences with CustomizedUser in your code (specially in your ManageController created by mvc).
From now on, you can easily access users table just like other tables:
var db = new CustomizedApplicationDbContext();
var user = db.CustomizedUsers.First(x=> x.OrgId == 10 || Email == "sth#yahoo.com");
And to get the current user OrgId, you can use something like this(without querying db):
var currentUserOrgId = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(User.Identity.GetUserId()).OrgId;
Hope this was helpful
You can get the current user in ASP.NET Identity as shown below:
ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext()
.GetUserManager<ApplicationUserManager>()
.FindById(System.Web.HttpContext.Current.User.Identity.GetUserId());
//If you use int instead of string for primary key, use this:
ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext()
.GetUserManager<ApplicationUserManager>()
.FindById(Convert.ToInt32(System.Web.HttpContext.Current.User.Identity.GetUserId()));
For getting custom properties from AspNetUsers table:
ApplicationUser user = UserManager.FindByName(userName);
string name = user.Name;
Hope this helps...
I have ASP.NET MVC 5 web project with E.F. 6.1.3.
I use IDbSet and its method Add to insert new data in my database. I also use context to save changes.
protected IDbSet<T> DbSet { get; set; }
public DbContext Context { get; set; }
private void Insert(T item)
{
this.DbSet.Add(item);
Context.SaveChanges();
}
When i insert new item in database
Is there any equivalent way in this interface to Sql Command.ExecuteScalar ?
In other words i need to get the Id of newly inserted item (my Id is first column and first row in current table).
You dont need ExecuteScalar (but you have to create your POCOs thru context.Set<T>().Create() method no, you dont have to, it works without proxy)
class MyPoco
{
[Key]
public int Id {get;set;}
}
...
var myPoco = context.Set<MyPoco>().Add(context.Set<MyPoco>().Create());
context.SaveChanges();
int newId = myPoco.Id;
However, if you have to have some direct store query, you can use context.ExecuteStoreQuery (its not on IDbSet, but on Context class)
var departments = context.ExecuteStoreQuery<string>
("select Name from Department where DepartmentID < #p0", 5);
EDIT (after you added code :) ):
You can add custom interface (or even base class) to your POCO with Id property:
public interface IId
{
int Id {get;}
}
class MyPoco
: IId
{
[Key]
public int Id {get;set;}
}
and update your Insert code like this:
private int Insert(T item)
where T : IId
{
this.DbSet.Add(item);
Context.SaveChanges();
return item.Id;
}
Note this doesnt work when you create your POCO simply by poco = new Poco() - this way, you give up lot of EF functionality (proxies), you have to use IDbSet<T>.Create() method) It work.
Or keep your item and take Id value after you send it to your Insert(item):
var myPoco = context.Set<MyPoco>().Add(context.Set<MyPoco>().Create());
context.Insert(myPoco);
int newId = myPoco.Id;
I'm new to Entity framework and Repository pattern. I'm trying to implement Repository Decorator pattern which contain basically Auditable and Archivable classes and extends the Attribute class. But when I add them on any entity class as:
[Auditable]
public class Student{
public int Id;
public string Name;
}
Using entity framework code first approach, the entity 'Student' supposed to generate columns Id,Name and the columns CreatedBy, Created, UpdatedBy and Updated from IAuditable interface. But what it was generating is only columns Id and Name.
So what is the correct way of implementing Repository Decorator pattern using entity framework and how to apply Auditable attribute on entity classes.?
Here I'm providing links to get some idea about repository decorator pattern.
https://efpatterns.codeplex.com/discussions/282699
https://efpatterns.codeplex.com/
Here is AuditableAttribute class extending Attribute:
using System;
namespace EntityFramework.Patterns.Extensions
{
public class AuditableAttribute : Attribute { }
}
Generic AuditableRepository class:
using System;
using System.Threading;
using EntityFramework.Patterns.Extensions;
namespace EntityFramework.Patterns.Decorators
{
public class AuditableRepository<T> : RepositoryDecoratorBase<T>
where T : class
{
public AuditableRepository(IRepository<T> surrogate) : base(surrogate) {
}
public override void Insert(T entity)
{
IAuditable auditable = entity as IAuditable;
if (auditable != null)
{
auditable.CreatedBy = Thread.CurrentPrincipal.Identity.Name;
auditable.Created = DateTime.Now;
}
base.Insert(entity);
}
public override void Update(T entity)
{
IAuditable auditable = entity as IAuditable;
if (auditable != null)
{
auditable.UpdatedBy = Thread.CurrentPrincipal.Identity.Name;
auditable.Updated = DateTime.Now;
}
base.Update(entity);
}
}
}
Here is the interface.
using System;
namespace EntityFramework.Patterns.Extensions
{
public interface IAuditable
{
string CreatedBy { get; set; }
DateTime? Created { get; set; }
string UpdatedBy { get; set; }
DateTime? Updated { get; set; }
}
}
So, what it would seem you have there is some dead code (or, more accurately, some not-yet-live code): it appears the author stubbed this out as a good idea some years ago, and it's been left on the vine ever since. You can see his last commit was almost 1.5 years ago, and the last one before that was almost the same time span.
Something that's not quite as widely downloaded from nuget.org but is more actively maintained is the excellent Highway.Data Framework, which my company uses on our projects – it even has an IAuditableInterceptor that's fully implemented! (Caveat: wish I could say that I've actually used this feature, but the rest of the framework is top-notch.)
Even better – if you're just learning EF – start with the basic EF6 nuget package and get comfortable with that first. That way, you won't be left guessing whether EF is fouling you up, or some unimplemented, third-party, library.
I am trying to update an entity which but when I call save changes nothing happens. Here's the code how I attached the entity. I am using EF6.1 and MVC5.1 by the way
var entity = db.Entity.Attach(existingEntity);
entity = new Entity(args0, args1, args2)
entity.Id = existingEntity.Id;
db.SaveChanges()
Here's the entity class:
public class Entity : Entity
{
public int Id { get; set; }
public string PropertyA { get; private set; }
public string PropertyB { get; private set; }
public string PropertyC { get; private set; }
}
public Entity(string args0, string args1, string args2)
{
this.PropertyA = args0;
this.PropertyB = args1;
this.PropertyC = args2;
}
Note that I did set the properties setter to private as I have some inner workings within the class. I'm thinking that the reason why EF can't update the entity is because I instantiate a new one though I did set its primary key. I did also try changing the State to Modified but it just running the "update script" but it doesn't really reflect the changes I made on each property
Any possible resolution for this scenario?
I am myself new to MVC and EF. But here goes.
Are you not mixing up your DAL and BLL by using private set?
Also, when you already have the existing entity why cant you just update the properties for entity directly? The way your class has been set up it can only be created, not modified.
Lastly, I think you have to explicitly tell EF that existingEntity has been modified.
var entity = new Entity(args0, args1, args2)
entity.Id = existingEntity.Id;
db.Entity.Attach(entity);
db.SaveChanges();
In EF, there is no object that represents the bridge table. But I need to delete/add record to the bridge table so I want to create a class that represents the bridge table
For example:
User: userID, name
Group: groupID, name
tblUserGroup: userID, groupID (bridge table)
I have the following:
public class EFDbContext : DbContext
{
public DbSet<User> User { get; set; }
public DbSet<Group> Group { get; set; }
public DbSet<GroupUser> tblGroupUser { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>().ToTable("User");
modelBuilder.Entity<Group>().ToTable("Group");
modelBuilder.Entity<GroupUser>().HasKey(a => new { a.UserID, a.GroupID });
modelBuilder.Entity<Group>()
.HasMany(u => u.User)
.WithMany(g => g.Group)
.Map(m =>
{
m.MapLeftKey("GroupID");
m.MapRightKey("NetworkUserID");
m.ToTable("tblGroupUser");
});
}
}
When I want to use the bridge table
context.tblGroupUser...(do sth)
The error says
Invalid object name 'dbo.GroupUsers'.
I think its saying that it doesn't know which table GroupUser map to
But when I add
modelBuilder.Entity<GroupUser>().ToTable("tblGroupUser");
The error change to
Each EntitySet must refer to a unique schema and table.
Now it doesn't allow me to map tblGroupUser 2 times. How can I fix this problem
Other info
public class EFGroupkUser
{
private EFDbContext context = new EFDbContext();
public IQueryable<GroupUser> tblGroupUser
{
get { return context.tblGroupUser; }
}
}
If your problem is only about add/delete from the junction table, you can simply do it and you don't need to tweak mappings of the model:
// ...
User u = db.Users.Find(id);
foreach (var g in u.Groups.ToList())
db.tblUserGroups.Remove(g);
Collection<GroupUser> gusers = new Collection<GroupUser>();
foreach (var item in model.GroupUsers)
{
tblGroupUser guo = new tblGroupUser();
guo.UserID = item.UserID;
guo.GroupID = item.GroupID;
gusers.Add(guo);
}
u.Groups = gusers;
db.SaveChanges();
You can perform any add/delete you want to a junction table like the above code. If your problem is just that, let the EF does its job by conventions and remove OnModelCreating
This question may be duplicate from this question.
If you want to add a group to a specific user.
var myUser = dbContext.Users.Find(id);
var myGroup= db.Groups.Single(group => group.GroupId == groupId);
myUser.Groups.Add(myGroup);
This will insert a record to tblUserGroup table.
You can do the vise versa too.
If you want to add a user to a specific group.
myGroup.Users.Add(myUser);
But if you really want tblUserGroup table to be generated in the edmx, just add an aditional column (Let's say IsActive) to the tblUserGroup table and then update the edmx. Now you can use the tblUserGroup class.