EF: Inserting already present record in many to many relationship - sql

For what I searched there are 2 ways to insert an already present record into a ICollection list:
group.Users.Add(db.Users.FirstOrDefault(x=> x.Id = 1));
var to_add = new User{Id: 1}; db.Users.Attach(to_add); group.Users.Add(to_add);
The problem with both the above approach is it makes a db call every time we want to add a record. While we already know the user's Id and the group's id and that's all it needs to create a relationship.
Imagine a long list to be added, both the above methods would make multiple calls to db.

So you have Groups and Users. Every Group has zero or more Users; every User has zero or more Groups. A traditional many-to-many relationship.
Normally one would add a User to a Group, or a Group to a User. However you don't have a Group, nor a User, you only have a GroupId and a UserId. and because of the large number of insertions you don't want to fetch the Users and the Groups of which you want to create relations
The problem is, if you could add the GroupId-UserId combination directly to your junction table, how would you know that you wouldn't be adding a Group-User relation that already exists? If you wouldn't care, you'd end up with twice the relation. This would lead to problems: Would you want them to be shown twice if you'd ask the Users of a Group? Which one should be removed if the relation ends, or should they all be removed?
If you really want to implement the possibility of double relation, then you'd need to Implement a a Custom Junction Table as described here The extra field would be the number of relations.
This would not help you with your large batch, because you would still need to fetch the field from the custom junction table to increment the NrOfRelations value.
On the other hand, if you don't want double relations, you'd have to check whether the value already exists, and you didn't want to fetch data before inserting.
Usually the number of additions to a database is far less then the number of queries. If you have a large batch of data to be inserted, then it is usually only during the initialization phase of the database. I wouldn't bother optimizing initialization too much.
Consider remembering already fetched Groups and Users in a dictionary, preventing them to be fetched twice. However, if your list is really huge, this is not a practical solution.
If you really need this functionality for a prolonged period of time consider creating a Stored Procedure that checks if the GroupId / UserId already exists in the junction table, and if not, add it.
See here For SQL code how to do Add-Or-Update
Entity Framework call stored procedure

Related

Database design to store ordered user photos?

For example,
user has [image1.jpg, image2.jpg ,image3.jpg]
user could reorder them to [image2.jpg, image1.jpg, image3.jpg], add to the end, delete from any position
I can think of 2 methods to store them:
just store as Array type in the database. when the user adds/deletes/reorders photos, overwrite the entire array in the database
store many photos rows with position column belongs to 1 user. on insert add to last position + 1. on delete, have to shift the positions after the deleted positions back - 1
What is the recommended design?
I think the most natural design in SQL would be a separate table:
create table userImages (
userImageId serial,
userId int references users(userId),
image varchar(255),
position int
);
As you have noticed, if you want positions to be gapless and ordered, then you need to update all the rows.
This has several features/advantages:
You can put the logic into a trigger or stored procedure so it is inside the database.
You can add additional information about the images, such as the date they were added or soft deletes.
The database can prevent duplicate images.
The alternative would be to store these as an array within a row in users. To maintain the ordering, you would basically need to do this in the application. That is, read the array, do deletes, inserts, and reorders, and then save the row again.
This has several features/disadvantages, such as:
The application has to be responsible for the column, instead of the database.
There is no place to put additional information about images.
I am generally biased toward the first approach, but there are some situations where the second is quite reasonable.
What I think is. if photo ordered by some attribute, (e.g. last edit time) you just select XXX order by attribute.
if photo ordered by user require, we have to use 'position' column.

SQL - Select data from three tables where one table has multiple foreign keys to the same primary key

I have the following tables and relations:
When I create a User, that user gets a CurrentWeekrow and that current week row in turn gets a CurrentWeekStatusrow. The user can add food items to the Foodtable and then can choose from these food items and select a few to insert in CurrentWeek.
In the client I want to grab CurrentWeekas an object that has a list of Foodobjects and a list of their corresponding status.
I am struggling as to how to make this happen. I think this can be done by making multiple queries to the database, one to fetch CurrentWeek and then from this extract all the FoodId's and make separate queries to fetch each Food. But this seems like a very bad solution.
The other solution I can think of is making a view with all the necessary data. But I don't know how to make this view and even if I manage to make the view I don't know how to separate each Food into different objects.
Do anyone know of a good way to accomplish this?
I use NodeJs as a REST API and Android Studio with retrofit to send REST calls.
After consulting StackOverflow and a few colleagues I changed the initial database schema into:
This was a design I initially chose to not go with as I thought adding one row on the CurrentWeek table for each user would be better than to add many rows for each user in the PlannedFood table. I see now however that this design have a few advantages as compared to the other design.
Designing it this way also solves my initial question as I can now grab all the rows in PlannedFood for a specific user, joining on FoodId and then map the Food data into a Foodobject on client-side.

Best practice for many to many data mapping

I am looking to find the best practice for many to many mapping in database.
For example I have two tables to be mapped. I create third table to store this mapping.
On UI I have several A to be mapped(or not) multiple with B. And I see two solutions for now:
1 - On every update for every record from A I will delete all mapped data for it and insert new data mapping.
Advantage: I store only mapped data.
Disadvantage: I need to use delete and insert statement every time.
2 - I need to add new bit column to AB table with name isMapped. And I will store all mapping for every record from A to every record from B. On save mapping action I will use only update statement.
Advantage: No need to delete and insert every time.
Disadvantage: Need to store unnecessary records.
Can you offer me best solution?
Thanks
between the 2 options you have listed I would go with option no 1, isMapped is not meaningful, if they are not mapped the records should not exists in the first place.
you still have one more option though:
DELETE FROM AB where Not in the new map
INSERT INTO AB FROM (New map) where NOT in AB
if these are a lot of maps I would delete and insert from the new mapping, otherwise I would just delete all then insert like you are suggesting.
I'd say anytime you see the second bullet point in your #2 scenario
"Need to store unnecessary records"
that's your red flag not to use that scenario.
Your data is modeled correctly in scenario 1, i.e. mapppings exist in the mapping table when there are mappings between records in A and B and mappings do not exist in the mapping table when there is not a mapping between those records in A and B.
Also, the underlying mechanics of an update statement are a delete and then an insert, so you are not really saving the database any work by issuing one over the other.
Lastly, speaking of saving the database work, don't try and do it at this stage. This is what they are designed for. :)
Implementing your data model correctly as you are in Scenario 1 is the best optimization you can make.
Once you have the basic normalized structure in place and have some test data, then you can start testing performance and refactoring if necessary. Adding indexes, changing data structures, etc.

User-specific database records

This is more of a theoretical questions. Anyways,
Assume that I have a database (50 tables)
And Data in ALL of those tables should be hold specifically to one user.
What I mean is, usually we do foreign keys for each table that is user-specific. and retrieving data using something like:
select Column1,Col2,Col3 from Table where UserId=#UserId
This clutters queries significantly. Is the other way of storing such data?
What you're referring to has a name. It's called multi-tenant. The link gives some general information on multi-tenant structures.
This all depends on your RDBMS though. Oracle provides a tool which makes this very easy.
The
WHERE User_ID = #User_ID
becomes a policy which you can apply to tables. You also create a protected stored procedure to update #User_id to ensure that it cannot be changed without authority. Then every query to a table with such a policy adds the where clause in the background. It's automatic and there's no way to avoid it.
There might be other ways, but I wouldn't say they are better. If every record in every table needs to belong to a specific user then you need a way to define that.
A possible method to reduce the number of UserId columns would be if you have child tables and you simply assumed that the parent table defined ownership and that it was implied that it's child records belonged to that user.
Example:
CarMake:
MakeId
MakeName
UserId
CarModel:
ModelId
MakeId
ModelName
Notice that CarModel does not have a UserId column, but you could assume that it inherits the same UserId of the parent CarMake record. If you cannot assume that children should always inherit the parent UserId then your original method is best.

SQL table design advice

I am building a community site where logon will be by email and members will be able to change their name/nick name.
Do you think I should keep member name/nick name in my members table with other properties of member or create another table, write member name/nick name on that table and associate member’s id.
I am in favour of second option because, I think it would be faster to pull members name from it.
Is it right/better way?
Update: reason is for other table is that I need to pull username for different sections. For example forums. Wouldn't it be faster to query a small table for each username for each post in a from topic?
I would keep it one table and set a unique constraint on Email in that table.
I can't see a single advantage in adding another table.
Why do you think the second option would be faster?
If nickname is a required one-to-one relation to member ID the appropriate place to store them is in the same table. This is still a indexed single-record search so it should be more-or-less as fast as your other option.
In fact, this solution would probably be faster, since you could get the nickname in the same SELECT as you get the other information.
Update to answer the update to the question:
The second table isn't any smaller in terms of the number of rows. The main factors in a SQL search are 1) number of records in the table and 2) number of possible matches from the indexed part of the search.
In this case, the number of records in your smaller table would be exactly the same as the larger table. And the number of possible matching records returned by the index will always be 1 because the member ID is unique.
The number of columns in the table you're searching is generally irrelevant to the time taken to return the data (the number of column you actually list in the SELECT statement can have an effect, but that's the same no matter which table you're searching).
SQL databases are very, very good at finding data. Structure your data correctly and let the database worry about getting it back to. Premature optimization is, as they say, the root of all evil.
Go with the first option: keep the name/nick name in the members table. There's no need to introduce an additional table, and the overhead of a join that goes with it, in this case.
Yes, associating member's ID to the other properties is the right way to go.
You can simply create an index on name to speed up your queries.