I make a very simple test, and right the method to click run test, but I have no idea why the table will insert two record
public class BookDbContext : DbContext
{
public BookDbContext(DbContextOptions<BookDbContext> options)
: base(options)
{ }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Books>().HasKey(x => x.ID)
.HasName("PK_Books");
modelBuilder.Entity<Books>().Property(x => x.ID)
.ValueGeneratedOnAdd();
base.OnModelCreating(modelBuilder);
}
}
Unit Test method :
[Fact]
public void SimpleTest()
{
var contextOptions = new DbContextOptionsBuilder<BookDbContext>()
.UseSqlServer("server=192.168.0.100;database=BookDB;User Id=sa;Password=password;Connection Timeout=120;TrustServerCertificate=True")
.Options;
BookDbContext db = new(contextOptions);
var book = new Books()
{
BookName = "My Book"
};
db.Add(book);
db.SaveChanges();
}
Table structure:
CREATE TABLE [dbo].[Books](
[Id] [int] IDENTITY(1,1) NOT NULL,
[BookName] [nvarchar](100) NULL,
CONSTRAINT [PK_Books] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON,
OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO
I have make a breakpoint, it just just run one time, but after check with table, it appear as two record
can I know reason?
Related
I have a (strange) situation.
I am using Entity Framework Code First but I have to attach to an existing Database.
I do not have to map every single table of the database in my object model. So I would like to migrate single Tables, whenever I need it.
I try to explain better. My database have about 100 tables, but I need to map in my model just 3 or 4. I have created my classes in c# and now I would like to map this classes with the tables I need.
Is it possible to do it? Do I have to do a migration?
UPDATE
Here my class:
public class PricePlan
{
public Guid Id { get; set; }
public String Name { get; set; }
public Double ActivationPrice { get; set; }
}
Here the context:
public class PublicAreaContext : DbContext
{
public DbSet<PricePlan> PricePlans { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<PricePlan>()
.HasKey(pp => new { pp.Id });
base.OnModelCreating(modelBuilder);
}
}
Here the table:
ALTER TABLE [dbo].[PricePlan](
[Id] [uniqueidentifier] NOT NULL,
[Name] [varchar](50) NULL,
[ActivationPrice] [decimal](5, 2) NULL,
... //Other columns
CONSTRAINT [PK_Price_Plans] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
possible: yes
migration: no. If you need migration you may have problem as in this case you haven't the __migrationHistory table (as the db is "existing" by opposite to "created by EF").
But the answer is definitively yes.
Create your classes, create a DbContext comprising DbSet, "et voilĂ ".
I have create a table with this schema :
CREATE TABLE [dbo].[A](
[KeyID] [uniqueidentifier] NOT NULL,
[OtherID] [uniqueidentifier] NULL,
[Info] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_TX_A] PRIMARY KEY CLUSTERED
(
[KeyID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
I have created this POCO Class :
public partial class A
{
public A()
{
}
public System.Guid KeyID { get; set; }
public Nullable<System.Guid> OtherID{ get; set; }
public string Info{ get; set; }
}
When I try to insert a new line in my table with Entity Framework :
[TestMethod]
public void TestAdd( )
{
A a = new A( );
Guid myKey = Guid.Parse("9B3CA1AC-279F-48CE-B693-D5329FF3AD14");
a.OtherID = myKey;
a.KeyID = myKey;
a.Info = "Test";
using( var database = new myConnection( ) )
{
database.A.Add( a );
database.SaveChangesAsync( ).Wait( );
}
}
It produces this SQL command :
DECLARE #generated_keys table([A] uniqueidentifier)
INSERT [dbo].[A]([OtherID], [Info])
OUTPUT inserted.[KeyID] INTO #generated_keys
VALUES (#0, #1)
SELECT t.[KeyID]
FROM #generated_keys AS g JOIN [dbo].[A] AS t ON g.[KeyID] = t.[KeyID]
WHERE ##ROWCOUNT > 0
Then it generates this error :
Can not insert the value NULL into column 'KeyID', table 'A. This column does not accept NULL values. INSERT failed.
It seems it doesn't take into account the primary key ID specified and it seems to believe that the primary key is auto incremented.
But this SQL statement works fine in SQL Server :
INSERT INTO A (KeyID, OtheriD, Info)
VALUES('9B3CA1AC-279F-48CE-B693-D5329FF3AD14', '9B3CA1AC-279F-48CE-B693-D5329FF3AD14', 'test')
Do you know what's wrong ?
Thanks for your help.
Your Entity Framework configuration is set up for database-generated primary key columns, that's why you also see in the SQL how EF attempts to retrieve the new KeyID value even though it hasn't set it. Your primary key column isn't database-generated, so this can never work.
If you let EF generate your database for you, you would have got a matching one. If you create your database manually, it has to match what EF thinks it should be, or you get errors like this.
You can chance your model to not treat the key column as database-generated with the DatabaseGenerated attribute, specifying DatabaseGeneratedOption.None.
use this code :
public void TestAdd( )
{
A a = new A( );
Guid myKey = Guid.NewGuid();//use this
a.OtherID = myKey;
a.KeyID = myKey;
a.Info = "Test";
using( var database = new myConnection( ) )
{
database.A.Add( a );
database.SaveChangesAsync( ).Wait( );
}
}
I have the following mapping:
public webpages_RolesMap()
{
// Primary Key
this.HasKey(t => t.RoleId);
// Properties
this.Property(t => t.RoleName)
.IsRequired()
.HasMaxLength(256);
// Table & Column Mappings
this.ToTable("webpages_Roles");
this.Property(t => t.RoleId).HasColumnName("RoleId");
this.Property(t => t.RoleName).HasColumnName("RoleName");
// Relationships
this.HasMany(t => t.UserProfiles)
.WithMany(t => t.webpages_Roles)
.Map(m =>
{
m.ToTable("webpages_UsersInRoles");
m.MapLeftKey("RoleId");
m.MapRightKey("UserId");
});
}
When I use Code First then this forces EF to create a webpages_UsersInRoles table that looks like this:
CREATE TABLE [dbo].[webpages_UsersInRoles](
[RoleId] [int] NOT NULL,
[UserId] [int] NOT NULL,
PRIMARY KEY CLUSTERED
(
[RoleId] ASC,
[UserId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
However the SimpleMembership classes created by Microsoft perform inserts that do not specify the column names and it expects the first column to be UserID and the second RoleId.
INSERT INTO webpages_UsersInRoles VALUES (1,3);
How can I make the mapping above create a table where UserID is column 1 and RoleId is column 2 ?
Note that I already tried adding this:
public partial class UsersInRoles
{
[Key, Column(Order = 0)]
public int UserId { get; set; }
[Key, Column(Order = 1)]
public int RoleId { get; set; }
}
But is seems to ignore this and still create the many to many with column names in the wrong order.
I think you must configure the many-to-many relationship from the other side to change the column order:
// UserProfileMap derived from EntityTypeConfiguration<UserProfile>
public UserProfileMap()
{
// ...
this.HasMany(t => t.webpages_Roles)
.WithMany(t => t.UserProfiles)
.Map(m =>
{
m.ToTable("webpages_UsersInRoles");
m.MapLeftKey("UserId");
m.MapRightKey("RoleId");
});
}
EF 5.0
I am working on a prototype to test hierarchyid and entity framework together. I have the following schema:
Create Table dbo.Employee
(
EmployeeId int identity not null,
Name nvarchar(100) not null,
Node hierarchyid not null,
NodePath as Node.ToString() persisted,
Level AS Node.GetLevel() persisted,
ManagerNode as Node.GetAncestor(1) persisted,
ManagerNodePath as Node.GetAncestor(1).ToString() persisted
);
Alter Table dbo.Employee
Add Constraint EmployeePK Primary Key NonClustered (EmployeeId);
Go
--Enforce Hierarchy
Alter Table dbo.Employee
Add Constraint EmployeeManagerNodeNodeFK Foreign Key (ManagerNode) References Employee(Node);
Go
Create Unique Clustered Index EmployeeDepthFirstIndex on dbo.Employee(Node);
Go
Create NonClustered Index EmployeeBreathFirstIndex on dbo.Employee(Level, Node);
Go
From my reading, the hierarchyid datatype isn't currently supported in EF, but some have suggested workarounds such as creating calculated columns (Node.ToString()) which I have done above.
Is there a way to setup EF so that it recognizes the Parent/Child relationship so I can effectively have a subordinates collection? e.g.
Employee.Subordinates
The only thing I can think of is to create a ManagerId column w/ a FK, but then I am effectively storing the hierarchy in two places.
Thanks for any help!
EF6 is now open source, so it is easy to add HierarcyID support. I have added it, too.
You can download the modifed source and the complied/signed dlls from codeplex:
http://entityframework.codeplex.com/SourceControl/network/forks/zgabi/efhierarchyidrc1 (sometimes the fork name changes)
Or from NuGet: https://www.nuget.org/packages/EntityFrameworkWithHierarchyId/
Currenty EF6 is in RC1 state, but I'll merge the modifications to every later releases of EF6.
I have the following model:
public class Employee
{
public int EmployeeId { get; set; }
[Required, MaxLength(100)]
public string Name { get; set; }
[Required]
public HierarchyId Node { get; set; }
public IQueryable<Employee> GetSubordinates(MyContext context)
{
return context.Employees.Where(o => Node == o.Node.GetAncestor(1));
}
}
public class MyContextInitializer : CreateDatabaseIfNotExists<MyContext>
{
protected override void Seed(MyContext context)
{
context.Database.ExecuteSqlCommand(
"ALTER TABLE [dbo].[Employees] ADD [ManagerNode] AS ([Node].[GetAncestor]((1))) PERSISTED");
context.Database.ExecuteSqlCommand(
"ALTER TABLE [dbo].[Employees] ADD CONSTRAINT [UK_EmployeeNode] UNIQUE NONCLUSTERED (Node)");
context.Database.ExecuteSqlCommand(
"ALTER TABLE [dbo].[Employees] WITH CHECK ADD CONSTRAINT [EmployeeManagerNodeNodeFK] " +
"FOREIGN KEY([ManagerNode]) REFERENCES [dbo].[Employees] ([Node])");
context.Employees.Add(new Employee { Name = "Root", Node = new HierarchyId("/") });
context.Employees.Add(new Employee { Name = "Emp1", Node = new HierarchyId("/1/") });
context.Employees.Add(new Employee { Name = "Emp2", Node = new HierarchyId("/2/") });
context.Employees.Add(new Employee { Name = "Emp3", Node = new HierarchyId("/1/1/") });
context.Employees.Add(new Employee { Name = "Emp4", Node = new HierarchyId("/1/1/1/") });
context.Employees.Add(new Employee { Name = "Emp5", Node = new HierarchyId("/2/1/") });
context.Employees.Add(new Employee { Name = "Emp6", Node = new HierarchyId("/1/2/") });
}
}
public class MyContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
}
Generated database:
CREATE TABLE [dbo].[Employees](
[EmployeeId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](100) NOT NULL,
[Node] [hierarchyid] NOT NULL,
[ManagerNode] AS ([Node].[GetAncestor]((1))) PERSISTED,
CONSTRAINT [PK_dbo.Employees] PRIMARY KEY CLUSTERED
(
[EmployeeId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [UK_EmployeeNode] UNIQUE NONCLUSTERED
(
[Node] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[Employees] WITH CHECK ADD CONSTRAINT [EmployeeManagerNodeNodeFK] FOREIGN KEY([ManagerNode])
REFERENCES [dbo].[Employees] ([Node])
Example to get the child nodes of Emp1 employee:
using (var c = new MyContext())
{
var firstItem = c.Employees.Single(o => o.Node == new HierarchyId("/1/"));
foreach (var table1 in firstItem.GetSubordinates(c))
{
Console.WriteLine(table1.EmployeeId + " " + table1.Name);
}
}
result:
4 Emp3
7 Emp6
Using varbinary(892) instead of hierarchyid.
EF recognizes varbinary returning byte array.
You can convert byte array to SqlHierarchyid type and use hyrarchy pod functions.
With this workaround you can use hierarchyid functions even in other databases.
See http://www.casavillar.com.br/blog with more details and links to nugget and github where you will find samples including MySql
Tables
CREATE TABLE [dbo].[Users](
[UserId] [int] IDENTITY(1,1) NOT NULL,
[UserName] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[Email] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[BirthDate] [smalldatetime] NULL,
[CountryId] [int] NULL,
CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED
([UserId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[TeamMember](
[UserId] [int] NOT NULL,
[TeamMemberUserId] [int] NOT NULL,
[CreateDate] [smalldatetime] NOT NULL CONSTRAINT [DF_TeamMember_CreateDate]
DEFAULT (getdate()),
CONSTRAINT [PK_TeamMember] PRIMARY KEY CLUSTERED
([UserId] ASC,
[TeamMemberUserId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
dbo.TeamMember has both UserId and TeamMemberUserId as the index key.
My goal is to show a list of Users on my View. In the list I want to flag, or highlight the Users that are Team Members of the LoggedIn user.
My ViewModel
public class UserViewModel
{
public int UserId { get; private set; }
public string UserName { get; private set; }
public bool HighLight { get; private set; }
public UserViewModel(Users users, bool highlight)
{
this.UserId = users.UserId;
this.UserName = users.UserName;
this.HighLight = highlight;
}
}
View
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<MvcPaging.IPagedList<MyProject.Mvc.Models.UserViewModel>>" %>
<% foreach (var item in Model) { %>
<%= item.UserId %>
<%= item.UserName %>
<%if (item.HighLight) { %>
Team Member
<% } else { %>
Not Team Member
<% } %>
How do I toggle the TeamMember or Not
If I add dbo.TeamMember to the EDM, there are no relationships on this table, how will I wire it to Users object?
So I am comparing the LoggedIn UserId with this list(SELECT TeamMemberUserId FROM TeamMember WHERE UserId = #LoggedInUserId)
EDIT
TeamMemberUserId is the UserId of the User that is a team member.
I named the table Users to avoid confusion with the System.We.Security User class.
I presume TeamMemberUserId is really the TeamId?
Why is there no relationship between the tables?
Why is pluralization messed up? User vs Users?
Sounds like you need something like:-
int userId = ... user Id for current user
var teams = context.TeamMember.Where(tm => tm.UserId == userId);
foreach (User other in ...)
{
int otherId = other.UserId;
bool highlight = teams.Any(team => context.TeamMember.Any(tm => tm.TeamId == team.TeamId && tm.UserId == otherId ));
...
}
Which would be much cleaner if you had the FK relationship in there.