Normalise table in Entity Framework Core and migrate existing data - sql-server

Let's suppose I have a table called Surveys (SurveyId, ... , SubmittedDate, LastEditedDate)
It's full of data and I now realise I should normalise it to get audit data into its own table, so I create a table SurveyAudits (SurveyAuditId, SubmittedDate, LastEditedDate)
When I create the table, I want to populate it with the data from Surveys.
Then I need to add a foreign key to Surveys (SurveyAuditId) so each survey links to its SurveyAudit.
Finally, I can drop the redundant columns from Surveys (SubmittedDate, LastEditedDate)
What do I add to the Up method to achieve this?
I suspect my approach so far may be unsuitable, so please steer me onto the correct path if that is the case!
Code:
public partial class CreateSurveyAudit : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "SurveyAudits",
columns: table => new
{
SurveyAuditId = table.Column<int>(type: "int", nullable: false).Annotation("SqlServer:ValueGenerationStrategy",SqlServerValueGenerationStrategy.IdentityColumn),
SubmittedDate = table.Column<DateTime>(type: "datetime2", nullable: false),
LastEditedDate = table.Column<DateTime>(type: "datetime2", nullable: false)
},
//I could get the data into the new table like so, but I would not have the relationship:
migrationBuilder.Sql("INSERT INTO SurveyAudits(SubmittedDate, LastEditedDate)
SELECT SubmittedDate, LastEditedDate FROM Surveys")
//so perhaps I could add the foreign key column first
migrationBuilder.AddColumn<int>(...);
migrationBuilder.CreateIndex(...);
migrationBuilder.AddForeignKey(...);
//then something like...
foreach (var survey in context.Surveys) { //but how do I access context?
survey.Add(new SurveyAudit(
SubmittedDate = survey.SubmittedDate,
LastEditedDate = survey.LastEditedDate)
}
context.SaveChanges();
}
}

You need to create a SurveyId column on your SurveyAudits table to make a relationship
Then use the following:
migrationBuilder.Sql("INSERT INTO SurveyAudits(SurveyId, SubmittedDate, LastEditedDate)
SELECT SurveyId, SubmittedDate, LastEditedDate FROM Surveys")

Related

Is any way to select a specific column from View with Entity Framework Core?

I have a View with a lot of columns and a class mapped to this view
public class MyClassConfig : IEntityTypeConfiguration<MyClass>
{
public void Configure(EntityTypeBuilder<MyClass> entity)
{
entity.ToTable(
name: "MyClass_View",
schema: DbContext.Schema);
}
}
In some queries, I do not need all the columns, and I want to select specific columns and that this would be done on the database side, like:
SELECT [v].[Prop1], [v].[Prop2]
FROM [schema].[MyClass_View] AS [v]
I create a query like this:
var items = context.MyClassView.Where(x => x.Id == id)
.Select(x => new
{
P1 = x.Prop1,
P2 = x.Prop2
});
But EF generates sql code with select all column from view. If I do the same query to the table this work perfectly. Is any way to do this for View?

Laravel belongsToMany with more then 3 primary keys

Actually I'm confused for the case, which relation fits best for my case, and in my opinion the best one is to have a table with 3 primary keys.
To be more specific.
I have a Person model in one of my db's, which has structure like
Person:
Id,
FirstName,
LastName,
...
And the other model Department, which has structure mentioned below
Department:
Id,
Name,
Description,
...
And goal is to set up Editors of schedule for each department and add also admins, whioch will approve requested schedules from editors. Editors and Admins are from same Person table, and if to assume, we need to map some Persons and department with some type.
I'm thinking about to have a mapping table with structure
PersonID,
DepartmentID,
Type (editor or admin)
And not sure, which relation fits best for this. If to have belongsToMany relation here with primary keys PersonID and DepartmentID, we will face an issue, because same Person possibly can be as editor and as admin for one single department. I have MS SQL server as a db.
Any suggestions will be appreciated
you can define many to many relations and use wherePivot method to select by pivot table Type column:
// Department model
public function admins()
{
return $this->belongsToMany(Person::class)->wherePivot('type', 'admin');
}
public function editors()
{
return $this->belongsToMany(Person::class)->wherePivot('type', 'editor');
}
// Person model
public function departmentsWhereIsAdmin()
{
return $this->belongsToMany(Department::class)->wherePivot('type', 'admin');
}
public function departmentsWhereIsEditor()
{
return $this->belongsToMany(Department::class)->wherePivot('type', 'editor');
}
// Note: we use methods names without parentheses
// usage for department
$department = Department::first(); // for example
dump($department->admins);
dump($department->editors);
// usage for person
$person = Person::first(); // for example
dump($person->departmentsWhereIsAdmin);
dump($person->departmentsWhereIsEditor);

How to get the ID from table by passing Name in Entity Framework in Silverlight mvvm?

In my Silverlight with MVVM project, I'm using Entity Framework. I have one table named Customer, with fields CustomerID, Username, age. I have inserted one row programmatically.
Here the CustomerID field is an auto-incremented one. So how can I get the CustomerID value by passing UserName that was inserted?
Need the LINQ Query to get it from Entity Framework..?
Any Help?
The auto-incremented ID should be set in the object, after you call SubmitChanges. That is, for example, newId here should contain the value:
var customer = new Customer { Username = "test", Age = 100 };
dataContext.InsertOnSubmit(customer);
dataContext.SubmitChanges();
var newId = customer.CustomerID;
If you need to get load it subsequently from the database, then use a simple query:
string name = "test";
var customer = dataContext.Customers.Where(customer => customer.Username == test).FirstOrDefault();
if (customer != null)
{
var newId = customer.CustomerID;
}

How to design a table which have many-to-many relationship with itself?

For example, A Users entity has a friends property, how can I design this friends property, in my thought there are 2 ways:
friends property is a String with all usernames splitted by "," in this way it's hard to read and modify.
friends property is a Set like Set<Users>, but in this way I don't know how to write in entities?
Anyone knows the best practise?
This is covered Enterprise Model Patterns by Hay.
A party represents a person (or an organization):
Party
id
name
A party can have a relationship to another party, over a time period:
PartyRelationship
fromPartyId
toPartyId
fromDate
toDate nullable
A basic diagram:
Party -< PartyRelationship >- Party
Sample SQL:
insert into party values (1, 'Jerry');
insert into party values (2, 'Neil');
insert into partyRelationship values (1, 2, getDate(), null);
If a User can have multiple friends you could annotate your User entity like this:
#Entity
public class User
{
#Id
private Long id;
private String name;
#ManyToMany
#JoinTable(
name = "user_friends",
joinColumns =
{ #JoinColumn(
name = "user_id") },
inverseJoinColumns =
{ #JoinColumn(
name = "friend_id") })
private Set<User> friends;
}
This way a table will get created for User and a join table for the relationship between Users. The User table will have 2 columns, 'id' and 'name'. The user_friend table will have 2 columns, 'user_id' and 'friend_id'. The columns in user_friend are both foreign keys to the User table.

Most efficient way to auto-hookup a foreign key in LINQ

I have two tables for tracking user sessions on my site. This is a gross oversimplification btw :
Campaign:
campaignId [int]
campaignKey [varchar(20)]
description [varchar(50)]
Session:
sessionDate [datetime]
sessionGUID [uniqueidentifier]
campaignId [int]
campaignKey [varchar(20)]
I want to insert a new record into Session, using LINQ :
var s = new Session();
dbContext.Session.InsertOnSubmit(s);
s.sessionDate = DateTime.Now;
s.sessionGUID = Guid.NewGuid();
s.campaignKey = Request.Params["c"];
// dont set s.campaignId here...
dbContext.SubmitChanges();
Notice that I am not currently setting campaignId in this code.
What I want is for something to automaticaly hookup the foreign key to the 'Campaign' table, and whatever does it must first add a new row to the 'Campaign' table if the campaign passed in has never been used before.
I have a few decisions to make and would really appreciate insight on any of them :
I don't know if I should use a trigger, a stored proc or do it in LINQ manually :
Trigger: slightly icky, never really liked using them, but would guarantee the 'campaignId' was updated by the time I need it
Stored proc: again slightly icky, my SQL is not great and I value the consistency of being able to do everything in LINQ as much as possible.
Linq manually: i'd have to keep a copy of the 'Campaign' table in memory and use a C# hashtable to do the lookup. i'd then have to worry about keeping that table up to date if another client added a new campaign.
My main two reasons for wanting this foreign key table is for a more efficient index on 'Session' for 'campaignId' so that I can do grouping faster. it just seems like it ought to be a lot faster if its just an integer column being grouped. The second reason is to give partners permissions to see only their campaigns through joins with other tables.
Before anyone asks I do NOT know the campaigns in advance, as some will be created by partners.
Most importantly: I am primarily looking for the most 'LINQ friendly' solution.
I would definitely recommend adding a nullable foreign key constraint on the Session table. Once you have that setup, it should be as simple as tacking on a method to the Session class:
public partial class Session
{
public void SetCampaignKey(string key)
{
// Use an existing campaign if one exists
Campaign campaign =
from c in dbContext.Campaigns
where c.campaignKey == key
select c;
// Create a new campaign if necessary
if (campaign == null)
{
campaign = new Campaign();
campaign.campaignKey = key;
campaign.description = string.Empty; // Not sure where this comes in
dbContext.Campaign.InsertOnSubmit(campaign);
}
// We can now set the reference directly
this.Campaign = campaign;
}
}
My LINQ may be a bit off, but something like this should work.
You can call SetCampaignKey() instead of manually setting the campaignKey property. When you call dbContext.SubmitChanges, the campaign will be added if necessary and the Session entry will be updated accordingly.
In this case, only the campaignId property would be set automatically. You could rely on a simple trigger to set campaignKey or do away with it. You could always retrieve the value by joining on the Campaign table.
Am I oversimplifying the problem?

Resources