I have 3 entities that are related (Account Groups to Account Categories to Accounts). I am trying to seed the database. The code below works for seeding Account Group and Account Category but I am unsure how to seed the next level which is account.
Database Diagram
var Revenue = new AccountGroup()
{
AccountGroupName = "Revenue",
AccountCategories = new List<AccountCategory>()
{
new AccountCategory { AccountCategoryName = "Base Business Build" },
new AccountCategory { AccountCategoryName = "Contract" },
new AccountCategory { AccountCategoryName = "Other" }
}
};
_context.AccountGroups.Add(Revenue);
_context.AccountCategories.AddRange(Revenue.AccountCategories);
await _context.SaveChangesAsync();
Examples of accounts in the Base Business Build Category would be:
Project work,
Vertical Sales.
Any help would be greatly appreciated.
Something like :
foreach(AccountCategories singleCategories in Revenue.AccountCategories)
{
_context.Account.AddRange(singleCategories.Acount)
}
await _context.SaveChangesAsync();
Related
I am new to firestore and am wondering if anyone could tell me whether this solution is viable for a many-to-many relationship. I have a collection of Rosters and collection of Students which are related Many-to-Many. As the information I most frequently need about a student is just their name, would it be viable to have a map of students like {<StudentID> : "Student Name"} stored in rosters, and so if I want to retrieve more detailed information about students in a roster, I retrieve the map's keys and iterate through them to retrieve each student's document individually?
I am basing my solution off of this answer.
I'd greatly appreciate any advice! Thank you
Update to this, it is working fine. Here is my code for the cloud function to update athlete names if anyone in the future needs:
export const onUserUpdate =
functions.firestore.document("users/{user}/athletes/{athlete}").onUpdate(
async (change) => {
const after = change.after.data();
const before = change.before.data();
const bid = change.before.id;
console.log("BID: ");
console.log(bid);
const userId: any = change.before.ref.parent.parent?.id;
console.log(`users/${userId}/rosters`);
if (after.athleteName != before.athleteName) {
console.log("Change name detected");
const snapshot =
await db.collection(
`users/${userId}/rosters`).where(
`athletes.${bid}`, ">=", "").get();
const updatePromises : Array<Promise<any>> = [];
snapshot.forEach((doc) => {
console.log(doc.id);
updatePromises.push(db.collection(`users/${userId}/rosters`)
.doc(doc.id).update(`athletes.${bid}`, after.athleteName)
);
});
await Promise.all(updatePromises);
}
});
I am learning Objection JS. I have a manyToMany relationship on an accounts and roles table that are related through an accounts_roles table. I was wondering if there was a way to update account roles on the account model by doing something like:
AccountOne.addRoles([roleId])
AccountOne.removeRoles([roleId])
AccountOne.updateRoles([roleId])
AccountOne.deleteRoles([roleId])
I searched online and went through the official objection documentation. So far I can do a GraphInsert, on my account model with a role object "x", and that creates a new role "x" with a relationship correctly defined in accounts_roles. But that always creates a new role. I would like to add and remove relationships between existing accounts and roles. Any help would be much appreciated.
You can use relate and unrelate to connect two rows together in a many-to-many relationship. Obviously, for this to work, you have to have your Models' relationMappings set up correctly. I have put a pair of example models too. It's critical that you match your key of your relationMappings to what you put in your $relatedQuery method to call relate/unrelate on.
Example Models
//Person and Movie Models
const { Model } = require('objection');
class Person extends Model {
static tableName = 'persons';
static get relationMappings() {
return {
movies: {
relation: Model.ManyToManyRelation,
modelClass: Movie,
join: {
from: 'persons.id',
through: {
from: 'persons_movies.person_id',
to: 'persons_movies.movie_id'
},
to: 'movies.id'
}
}
};
}
}
class Movie extends Model {
static tableName = 'movies';
static get relationMappings() {
return {
persons: {
relation: Model.ManyToManyRelation,
modelClass: Person,
join: {
from: 'movies.id',
through: {
from: 'persons_movies.movie_id',
to: 'persons_movies.person_id'
},
to: 'persons.id'
}
}
};
}
}
Relate Example
In the case of a many-to-many relation, creates a join row to the join table.
const person = await Person
.query()
.findById(123);
const numRelatedRows = await person
.$relatedQuery('movies')
.relate(50);
// movie with ID 50 is now related to person with ID 123
// this happened by creating a new row in the linking table for Movies <--> Person
Unrelate Example
For ManyToMany relations this deletes the join row from the join table.
const person = await Person
.query()
.findById(123)
const numUnrelatedRows = await person
.$relatedQuery('movies')
.unrelate()
.where('id', 50);
// movie with ID 50 is now unrelated to person with ID 123
// this happened by delete an existing row in the linking table for Movies <--> Person
I'm using EF6 have some confusion on seeding a many to many relationship.
I have the following:
A User has many saved ChartQueries (that they can execute to get a chart).
A ChartQuery typically belongs to only one user, but there are several "shared" ChartQuerys that every User can execute. As a result I set up a many to many relationship using a join table UserChartQuery. The tables are up in the database just fine at 1-to-many on each side of the join table.
However, I'm not quite understanding how to seed or use this relationship. I don't want to end up with several duplicates of the "shared" ChartQuerys (a duplicate for each User). Instead, there should only be a single row for each "shared" ChartQuery that is a part of each User's SavedChartQueries collection (along with other, non-shared ChartQuerys that belong to that User only).
It seems like I'm forced to duplicate for each user:
var sharedChartQuery = new ChartQuery { ... };
var nonSharedChartQuery = new ChartQuery { ... };
var userOneChartQueryOne = new UserChartQuery { User = userOne, ChartQuery = sharedChartQuery };
var userTwoChartQueryOne = new UserChartQuery { User = userTwo, ChartQuery = sharedChartQuery };
var userTwoChartQueryTwo = new UserChartQuery { User = userTwo, ChartQuery = nonSharedChartQuery };
context.UserChartQueries.Add(userOneChartQueryOne);
context.UserChartQueries.Add(userOneChartQueryTwo);
context.UserChartQueries.Add(userTwoChartQueryTwo);
So first of all is this the right way to seed (through UserChartQueries table directly) or should I seed each User's SavedChartQueries navigation property?
And will this result in duplicate sharedChartQuery in the join table for each User? If so is there any way to avoid this?
Ok I understand how this works now. The following works as expected:
var userOne = new User {};
var userTwo = new User {};
var chartQuery = new ChartQuery { };
context.Users.Add(userOne);
context.Users.Add(userTwo);
context.UserChartQueries.Add(new UserChartQuery { User = userOne, ChartQuery = chartQuery });
context.UserChartQueries.Add(new UserChartQuery { User = userTwo, ChartQuery = chartQuery });
context.ChartQueries.Add(chartQuery);
The last line adds it to the table where the record actually resides. Checking the join table in SSMS shows that it only holds the foreign keys and nothing else. There are no duplicates.
I am relatively new to the EF and have the following entity model above which consists of an Asset and a Country. An Asset can belong in many countries and thus has a many-to-many relationship with country (has a join table in the database with two fields both as primary keys).
I want to be able to do the following:
Firstly when I retrieve an asset (or assets) from the model I want to get the respective countries that its associated with. I would then like to be able to bind the countries list to an IEnumerable. Retrieving the countries in this way provides me with an EntityCollection of country objects which has extension method for ToList(). Therefore not sure If I am going down the right avenue with this one. Here is my GetAll method:
public IEnumerable<Asset> GetAll()
{
using (var context = CreateAssetContext())
{
var assetEntities = context.Assets.Include("Countries").ToList();
return AssetMapper.FromEntityObjects(assetEntities);
}
}
Secondly I want to be able to select a list of countries where the AssetId == some value.
Finally I want to be able to update the list of countries for a given Asset.
Many thanks.
Firstly when I retrieve an asset (or assets) from the model I want to
get the respective countries that its associated with. I would then
like to be able to bind the countries list to an IEnumerable.
Not sure if I understand that correctly, but EntityCollection<T> implements IEnumerable<T>, so you don't have to do anything special, you just can use Asset.Countries after you have loaded the assets including the countries.
Secondly I want to be able to select a list of countries where the
AssetId == some value.
using (var context = CreateAssetContext())
{
var countries = context.Countries
.Where(c => c.Assets.Any(a => a.AssetId == givenAssetId))
.ToList();
}
Or:
using (var context = CreateAssetContext())
{
var countries = context.Assets
.Where(a => a.AssetId == givenAssetId)
.Select(a => a.Countries)
.SingleOrDefault();
}
The second option is OK (not sure if it's better than the first from SQL viewpoint) because AssetId is the primary key, so there can be only one asset. For querying by other criteria - for example Asset.Name == "XYZ" - where you could expect more than one asset I would prefer the first option. For the second you had to replace Select by SelectMany and SingleOrDefault by ToList and use Distinct to filter out possible duplicated countries. The SQL would probably be more complex.
Finally I want to be able to update the list of countries for a given
Asset.
This is more tricky because you need to deal with the cases: 1) Country has been added to asset, 2) Country has been deleted from asset, 3) Country already related to asset.
Say you have a list of country Ids ( IEnumerable<int> countryIds ) and you want to relate those countries to the given asset:
using (var context = CreateAssetContext())
{
var asset = context.Assets.Include("Countries")
.Where(a => a.AssetId == givenAssetId)
.SingleOrDefault();
if (asset != null)
{
foreach (var country in asset.Countries.ToList())
{
// Check if existing country is one of the countries in id list:
if (!countryIds.Contains(country.Id))
{
// Relationship to Country has been deleted
// Remove from asset's country collection
asset.Countries.Remove(country);
}
}
foreach (var id in countryIds)
{
// Check if country with id is already assigned to asset:
if (!asset.Countries.Any(c => c.CountryId == id))
{
// No:
// Then create "stub" object with id and attach to context
var country = new Country { CountryId = id };
context.Countries.Attach(country);
// Then add to the asset's country collection
asset.Countries.Add(country);
}
// Yes: Do nothing
}
context.SaveChanges();
}
}
Edit
For the price of a second roundtrip to the database you can probably use this simpler code:
using (var context = CreateAssetContext())
{
var asset = context.Assets.Include("Countries")
.Where(a => a.AssetId == givenAssetId)
.SingleOrDefault();
if (asset != null)
{
// second DB roundtrip
var countries = context.Countries
.Where(c => countryIds.Contains(c.CountryId))
.ToList();
asset.Countries = countries;
context.SaveChanges();
}
}
EF's change detection should recognize which countries have been added or deleted from the asset's country list. I am not 100% sure though if the latter code will work correctly.
Whats the specific question here? Are you not being able to do that?
do you want to select the countries in an asset or the countries that have a certain asset?
to update its simple, just change stuff and then context.SaveChanges() will commit to the database.
I have a default Entity Framework model that holds all of my default tables for my product, and that all customers share in common. However, on some customers, I have some custom tables that exist for only that customer, but they relate to the default product's tables. I have a second Entity Framework model to hold these custom tables.
My question is how can I make a Linq to Entities query using Join so I can relate the entities from my default model to the tables on my custom model? I don't mind not having the Navigation properties from the custom entity to the entities on the default model; I just need a way to query both models in a single query.
Below is the code:
using (ProductEntities oProductDB = new ProductEntities())
{
using (ProductEntitiesCustom oProductCustomDB = new ProductEntitiesCustom())
{
var oConsulta = oProductCustomDB.CTBLCustoms
.Where(CTBLCustoms => CTBLCustoms.IDWOHD >= 12)
.Join(oProductDB.TBLResources,
CTBLCustoms => new
{
CTBLCustoms.IDResource
},
TBLResources => new
{
TBLResources.IDResource
},
(CTBLCustoms, TBLResources) => new
{
IDCustom = CTBLCustoms.IDCustom,
Descricao = CTBLCustoms.Descricao,
IDWOHD = CTBLCustoms.IDWOHD,
IDResource = CTBLCustoms.IDResource,
ResourceCode = TBLResources.Code
});
gvwDados.DataSource = oConsulta;
}
}
I get a The specified LINQ expression contains references to queries that are associated with different contexts error.
EDIT
Could I merge the 2 ObjectContext into a third, and then run the Linq query?
Tks
EDIT
Below is the code that worked, using the AsEnumerable() proposed solution:
using (ProductEntities oProductDB = new ProductEntities())
{
using (ProductEntitiesCustom oProductCustomDB = new ProductEntitiesCustom())
{
var oConsulta = (oProductCustomDB.CTBLCustoms.AsEnumerable()
.Where(CTBLCustoms => CTBLCustoms.IDWOHD >= 12)
.Join(oProductDB.TBLResources,
CTBLCustoms => new
{
CTBLCustoms.IDResource
},
TBLResources => new
{
TBLResources.IDResource
},
(CTBLCustoms, TBLResources) => new
{
IDCustom = CTBLCustoms.IDCustom,
Descricao = CTBLCustoms.Descricao,
IDWOHD = CTBLCustoms.IDWOHD,
IDResource = CTBLCustoms.IDResource,
ResourceCode = TBLResources.Code
})).ToList();
gvwDados.DataSource = oConsulta;
}
}
I added the AsEnumerable() as suggested, but I had to add the ToList() at the end so I could databind it to the DataGridView.
You can't do this in L2E. You could bring this into object space with AsEnumerable(), and it would work, but possibly be inefficient.
Merging the ObjectContexts is possible, and would work, but would need to be done manually.