Insert in the link table many to many in Entity Framework - c#

I have 3 tables
Operator
OperatorWarehouse
Warehouse
| Operators | | OperatorsWarehouses | | Warehouses |
| OperatorID | - | OperatorID | - | WarehouseID |
| EmployeeID | | WarehouseID | | Warehouse |
So basically in my entity framework the "OperatorsWarehouses" table does not appear...
There is already data in the Warehouses table, I only need to insert in Operators and OperatorsWarehouses to make the relation.
This is my code
using (InventoryContext db = new InventoryContext ())
{
Employee employee = new Employee();
employee.EmployeeID = Convert.ToInt32(ddlOperators.SelectedValue);
var operator = new Operator();
operator.EmployeeID = employee.EmployeeID ;
db.Operator.Add(operator);
db.SaveChanges();
ddlOperators.DataBind();
}
I already tried
operator.Warehouses.Add(new Warehouse());
But that is going to insert in the warehouses table and i don't want to do that, I want to insert only the operator on that table

You Should Provide the Id for Warehouse of the Operator , if the Warehouse you are adding has 0 as its id then it's considered a new Warehouse.
you can add a dropdown list for the warehouses in your UI that the user selects once they are adding an operator.
using (InventoryContext db = new InventoryContext ())
{
Employee employee = new Employee();
employee.EmployeeID = Convert.ToInt32(ddlOperators.SelectedValue);
var wareHouseId = Convert.ToInt32(ddlWarehouses.SelectedValue);
var operator = new Operator();
operator.EmployeeID = employee.EmployeeID ;
operator.Warehouses.add(new Warehouse(){Id=wareHouseId});
db.Operator.Add(operator);
db.SaveChanges();
ddlOperators.DataBind();
}

Add [NotMapped] in your defintion table :
Something like this
[NotMapped]
public List<Warehouse> Warehouses;

Entity framework will hide the relationship table when it's a "pure" many to many relationship. So you won't be seing the OperatorsWarehouses table, it will be handled by EF.
To add relationships you just add entities to entities, so you can add an operator to a warehouse or you can add a warehouse to an operator.
In your specific case you'll need to add an existing warehouse to the operator, or an existing operator to the warehouse. Something like this:
int whId = 1; //warehouse with id 1
db.Warehouses.FirstOrDefault(x => x.WarehouseID ==
whId ).Operators.Add(operator);
note: be careful about the FirstOrDefault which will return null if there's no warehouse with id 1

Related

Associate values of one list with the ones of another list with linq

I have two lists, one holding some information about customers and one other table with some more information about the financial status of a customer (1-to-1 relationship).
Customer table:
Id
Name
Address
Fincance table:
Id
CustomerId
Salary
My goal is to link each salary to the list of customers (not all customers have an associated recored in the finance table).
I am receiving all my customers and finances like this:
IEnumerable<Customer> customers= await _customerService.GetCustomers();
IEnumerable<CustomerDTO> customerDTOs = _mapper.Map<IEnumerable<Customer>, IEnumerable<CustomerDTO>>(kunden); // Map to CustomerDTO which contains a property for salary
IEnumerable<Finance> finances= await _financeService.GetFinances();
Example:
+----+-----------+---------+ +----+------------+--------+
| Id | Name | Address | | Id | CustomerId | Salary |
+----+-----------+---------+ +----+------------+--------+
| 1 | Microsoft | foo 1 | | 1 | 1 | 8,650$ |
| 2 | Apple | foo 2 | | 3 | 2 | 7,880$ |
| 3 | Testla | foo 3 | +----+------------+--------+
+----+-----------+---------+
Note: I am mapping Customer to a CustomerDTO which has a field Salary. That field should be filled with the ones of the Finance table. I cannot change the design of my tables and there is a reason behind the table design which I am not going to talk about due to simplicity. I am just interested if it is possible to use linq to do this kind of operation.
Yes, it's possible - you have the list of customers and the list of salaries.
To join them manually, you can just do
customers.Select(x=> new {
x.Id,
x.Name,
x.Address,
Salary = salaries.SingleOrDefault(y=>y.CustomerId==x.Id)?.Salary
}).ToList();
This will create a new list with the info joined.
You can also do a straight join as well:
https://learn.microsoft.com/en-us/dotnet/csharp/linq/perform-inner-joins
Another way of doing it besides the way that Matt explained is like this:
finances.ToList().ForEach(x => customerDTOs.Where(y => y.Id == x.CustomerId).First().Salary = x.Salary);
You can also do with Left outer join as well:
https://learn.microsoft.com/en-us/dotnet/csharp/linq/perform-left-outer-joins
From above link:
You have the list of customers and the list of Finance so Can you please try this:
var abc = from c in customers
join fa in Fincance on c.Id equals fa.CustomerId into fin
from fa in fin.DefaultIfEmpty()
select new
{
c.Id,
c.Name,
c.Address,
salary = fa != null ? fa.Salary : null
};

Entity ORM Joining Two Tables Off ID ForeignKey given non-foreignkey?

I have a string, name.
I have two tables:
Table 1:
|---------------------|------------------|
| ID | PadName |
|---------------------|------------------|
| 12 | "Hello" |
|---------------------|------------------|
Table 2
|------------------------------------------|------------------|
| MetaDataID (FK to ID in table1) | .......... |
|------------------------------------------|------------------|
| 12 | Other Data..
|------------------------------------------|------------------|
Example Query:
Select ID from table1 given a padName the join that ID with table2.
I'm using entity framework in C# and what I want is to feed in a PadName in Table 1 and then get all the associated Table 2 data where the ID fields match (since table2 has an FK relationship to table 1).
I've seen some example code like the following:
var query = _context.PadMetaData
.Where(x => x.PadName == padName).Select(p => new { p.id });
Then I want to take that id result and join it with the MetaDataId in table2.
But I can't seem to achieve what I want.

Is it possible to fetch a link table without fetching all links?

Ok, so first of I would like to say that I'm using NHibernate for my project, and in this project we have (among other things) a sync function (to sync from a central MSSQL database to a local SQLite). Now I know that NHibernate was not made to sync databases, but I would like to do this anyways.
I have a medium large database model so I can't add it here, but the problem is that I have two datatables, and one link table to link them both.
Database model:
| Product | | ProductLinkProducer | | Producer |
|--------------------| |---------------------| |---------------------|
| Id | | LinkId | | Id |
| Name | | Product | | Name |
| ProductLinkProducer| | Producer | | ProductLinkProducer |
Database:
| Product | | ProductLinkProducer | | Producer |
|---------| |---------------------| |----------|
| Id | | LinkId | | Id |
| Name | | ProductId | | Name |
| | | ProducerId | | |
So during the sync, I first copy all data from the Product table, and then from the Producer table (basically var products = session.Query<Products>().ToList()). This is done by NHibernate in a single statement each:
select
product0_.id as id2_,
product0_.name as name2_
from
Product product0_
Now I have to evict all items from the first session (products.ForEach(x => session.Evict(x));)
And then the save (products.ForEach(x => syncSession.save(x));) is one insert per row (as expected).
So when saving the data in the link table I would have wished that there also would be just a single select. However that is not the case. Because first it makes a select ... as above. But now before every row to insert it does even more select for the Product and for the Producer.
So it will look something like:
Products:
select
insert (id 1)
insert (id 2)
Producer:
select
insert (id 101)
insert (id 102)
ProdLinkProducer:
select
select id 1 from Products
select id 1 from Products
select id 101 from Producer
select id 2 from Products
select id 2 from Products
select id 102 from Producer
select id 102 from Producer
insert
insert
So is there anyway avoiding this behavior?
EDIT
To better explain what I have done, I have created a small test project. It can be found here: https://github.com/tb2johm/NHibernateSync
(I would have preferred to add only a ghist, but I think that it might have left out to much data, sorry...)
EDIT2
I have found out one way to make it work, but I don't like it.
The way this solution works is to in the database model create a ProductLinkProducerSync table, that doesn't contain any links, but just the values, and avoid synchronizing the ordinary link tables, but just the "sync" tables. But as I said I don't like this idea, since if I change anything in the database, I have kind of the same data in two places that I need to update.
I was unable to find NHibernate out of the box way of doing what you are asking.
However I was able to get the desired behavior (I guess something is better than nothing:) by manually rebinding the FK references (proxy classes) to the new session:
var links = session.Query<ProductLinkProducer>().ToList();
links.ForEach(x => session.Evict(x));
foreach (var link in links)
{
link.Product = syncSession.Get<Product>(link.Product.Id);
link.Producer = syncSession.Get<Producer>(link.Producer.Id);
syncSession.Save(link);
}
syncSession.Flush();
Here is the generalized version using NHibernate metadata services:
static IEnumerable<Action<ISession, T>> GetRefBindActions<T>(ISessionFactory sessionFactory)
{
var classMeta = sessionFactory.GetClassMetadata(typeof(T));
var propertyNames = classMeta.PropertyNames;
var propertyTypes = classMeta.PropertyTypes;
for (int i = 0; i < propertyTypes.Length; i++)
{
var propertyType = propertyTypes[i];
if (propertyType.IsAssociationType && !propertyType.IsCollectionType)
{
var propertyName = propertyNames[i];
var propertyClass = propertyType.ReturnedClass;
var propertyClassMeta = sessionFactory.GetClassMetadata(propertyClass);
yield return (session, target) =>
{
var oldValue = classMeta.GetPropertyValue(target, propertyName, EntityMode.Poco);
var id = propertyClassMeta.GetIdentifier(oldValue, EntityMode.Poco);
var newValue = session.Get(propertyClass, id);
classMeta.SetPropertyValue(target, propertyName, newValue, EntityMode.Poco);
};
}
}
}
and applying it to your Sync method:
private static void Sync<T>(string tableName, ISession session, ISession syncSession)
{
Console.WriteLine("Fetching data for ####{0}####...", tableName);
var sqlLinks = session.Query<T>();
var links = sqlLinks.ToList();
Console.WriteLine("...Done");
Console.WriteLine("Evicting data...");
links.ForEach(x => session.Evict(x));
Console.WriteLine("...Done");
Console.WriteLine("Saving data...");
var bindRefs = GetRefBindActions<T>(syncSession.SessionFactory).ToList();
foreach (var link in links)
{
foreach (var action in bindRefs) action(syncSession, link);
syncSession.Save(link);
}
Console.WriteLine("...Flushing data...");
syncSession.Flush();
Console.WriteLine("...Done");
Console.WriteLine("\n\n\n");
}

Updating entity with another entity in C# Entity Framework

I have a bunch of entities that need to be updated to match entities of the same class in a different database. For example:
Database1 TableA:
Id| User | FirstName| LastName
1 | Geekguy123 | Fred | Smith
Database2 TableA:
Id| User | FirstName| LastName
34| Geekguy123 | Frederick| Smith
How can I update database1 for Geekguy123 so the new FirstName is Frederick? The ids are different but the User is unique.
To be clear, there are dozens of properties on the entity, which I don't want to update manually. Maybe SQL would be easier?
Just query in database 1 for the record you want. Get its FirstName property and then query the record in database 2 and then update firstname field with the one you got from database 1. And then submit your change.
Db1Context c1 = new Db1Context();
var userToUpdateWith = c1.Users.Single(u => u.User == "Geekguy123")
Db2Context c2 = new Db2Context();
var userToUpdate = c2.Users.Single(u => u.User == "Geekguy123")
Since you got to set many properties, you can do the following.
string[] properties = new string[]{"FirstName","LastName"};
foreach(var property in properties){
object value = userToUpdateWith.GetType().GetProperty(property).GetValue(userToUpdateWith, null);
userToUpdate.GetProperty(property).SetValue(userToUpdate, value, null);
c2.SaveChanges();
Here you go - the pass-through SQL that you can use.
If the table name is really Database1, then replace Table1, Table2 accordingly.
UPDATE t1
SET t1.FirstName = t2.FirstName
FROM Database1.dbo.Table1 AS t1
INNER JOIN Database2.dbo.Table2 AS t2
ON t1.User = t2.User
And the passthrough would be like this:
using (var context = new YourDataContext())
{
context.Database.ExecuteSqlCommand(sqlString);
}
Turns out, there were actually a couple hundred properties. I ended up deleting and re-adding the entity with the new values.

LINQ Group By selecting with many-to-many association table

I have two models, Plans and Bookmarks, which are associated in a many-to-many relationship with an association table in the database. Specifically I'm looking at the situation where a Bookmark is associated with multiple Plans, like below...
BookmarkID | PlanID
A | 1
A | 2
B | 2
I'd want to select all BookmarkIDs where there is no association with a particular PlanID. So if PlanID = 1, I'd want to select B but not A.
For bonus points, I can easily take the BookmarkID result and get all the Bookmarks with a second linq query, but it would be cool to do this inline with a select function or soemthing.
I believe you want to use All like this:
int planId = 1;
var query = from b in context.Bookmarks
where b.Plans.All(p => p.PlanID != planId)
select b.BookmarkID;

Categories

Resources