Entity Framework Linking tables - entity-framework-5

I’m using Entity Framework 5.0,
Scenario
"Organisation" has a list of "clients" and a list of "Periods" and a "CurrentPeriodID" At the start of each period some or all of the "Clients" are associated with that "Period", this I have done using a link table and this works OK so when I do "Organisation->Period->Clients" I get a list of "Clients" for the "Period".
Next I need to add some objects ("Activities") to the "Clients" for a "Period" so I get "Organisation->Period->Client->Activates" this won’t be the only one there will eventually be several other navigation properties that will need to be added to the "Clients" and the "Activities" and all of them have to be "Period" related, I also will have to be able to do (if possible) "Organisation->Period-Activities".
Question
What would be the best way of implementing the "Activities" for the "Organisation->Period-Client", I Don’t mind what way it is done Code First reverse Engineering etc. Also on the creation of the "Organisation" object could I load a current "Period" object using the "CurrentPeriodID" value which is stored in the "Organisation" object.
Thanks

To me this sounds like you need an additional entity that connects Period, Client and Activity, let's call it ClientActivityInPeriod. This entity - and the corresponding table - would have three foreign keys and three references (and no collections). I would make the primary key of that entity a composition of the three foreign keys because that combination must be unique, I guess. It would look like this (in Code-First style):
public class ClientActivityInPeriod
{
[Key, ForeignKey("Period"), Column(Order = 1)]
public int PeriodId { get; set; }
[Key, ForeignKey("Client"), Column(Order = 2)]
public int ClientId { get; set; }
[Key, ForeignKey("Activity"), Column(Order = 3)]
public int ActivityId { get; set; }
public Period Period { get; set; }
public Client Client { get; set; }
public Activity Activity { get; set; }
}
All three foreign keys are required (because the properties are not nullable).
Period, Client and Activity can have collections refering to this entity (but they don't need to), for example in Period:
public class Period
{
[Key]
public int PeriodId { get; set; }
public ICollection<ClientActivityInPeriod> ClientActivities { get; set; }
}
You can't have navigation properties like a collection of Clients in Period that would contain all clients that have any activities in the given period because it would require to have a foreign key from Client to Period or a many-to-many link table between Client and Period. Foreign key or link table would only be populated if the client has activities in that Period. Neither EF nor database is going to help you with such a business logic. You had to program this and ensure that the relationship is updated correctly if activities are added or removed from the period - which is error prone and a risk for your data consistency.
Instead you would fetch the clients that have activities in a given period 1 by a query, not by a navigation property, for example with:
var clientsWithActivitiesInPeriod1 = context.Periods
.Where(p => p.PeriodId == 1)
.SelectMany(p => p.ClientActivities.Select(ca => ca.Client))
.Distinct()
.ToList();

Related

Cosmos Document query to locate latest record per type

I have a collection where I am storing the timestamp and its latest location with the following class:
public class TrackingInfo
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("_partition_key")]
public string _PartitionKey { get; set; }
[JsonProperty("asset_id")]
public string AssetId { get; set; }
[JsonProperty("unix_timestamp")]
public double UnixTimestamp { get; set; }
[JsonProperty("timestamp")]
public string Timestamp { get; set; }
[JsonProperty("location")]
public Point Location { get; set; }
}
which is partitioned by _PartitionKey which contains a construct like this:
tracking._PartitionKey = $"tracking_{tracking.AssetId.ToLower()}_{DateTime.Today.ToString("D")}";
Looks like there is no way to do a Group by on the collection.
Can someone please help me create a SQL document query to find the latest entry for each AssetId and its Location and Timnestamp when the data was recorded.
Update 1:
what if I change the _PartitionKey to represent per day something like below:
tracking._PartitionKey = $"tracking_{DateTime.Today.ToString("D")}";
would it make it easier to get all assets and its latest tracking record?
As per my comment, my suggestion would be to solve your problem differently.
Assumption: You have a large number of assetIds and don't know the values beforehand:
Have one document that represents the latest state of your asset
Have another document that represents the location events of your asset
Update the first document whenever there is a new location event
You can put both types of documents in the same collection or separate them - both approaches have benefits. I would probably separate them.
Then do a query "what assets are within 1km of xxx" (Querying spatial types)
Sidenote: It might be a good idea to use the assetId as partitionKey instead of your combined key. Using such a key is very bad for queries
If you only have very few assetIds, you can use those to only find the latest updates by using and ordering by the timestamp field. This will only return the last item
Cosmos DB doesn't support group by feature,you could vote up this.
Provide a third-party package [documentdb-lumenize for your reference which supports group by feature,it has .net example:
string configString = #"{
cubeConfig: {
groupBy: 'state',
field: 'points',
f: 'sum'
},
filterQuery: 'SELECT * FROM c'
}";
Object config = JsonConvert.DeserializeObject<Object>(configString);
dynamic result = await client.ExecuteStoredProcedureAsync<dynamic>("dbs/db1/colls/coll1/sprocs/cube", config);
Console.WriteLine(result.Response);
You could group by assetId column and get the max timestamp.

EF6 and MVC5: Using two fields as a combined key

I have several objects (Product, Rule, PriceDetail, etc.) that manage and store information in a CRUD application. I want a way to keep a log of when the data is updated, and to that end I've created an Update class, referenced as ICollection<Update> Updates within each data class.
When the tables are all generated, EF creates a FK for each class in the Updates table (Product_ID, Rule_ID, etc.). This seems horribly inefficient. Could I use a two-field key, such as enum ObjectType and long ID? Alternately, can I use string ID and force a pattern where the first N characters of the string identify the referencing object? If the latter, can the database auto-increment the string value?
Here's some example code, trimmed for placement here:
public class Update
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long ID { get; set; }
public string Reason { get; set; }
public DateTime TimeOfUpdate { get; set; }
public long Product_ID { get; set; }
public long Rule_ID { get; set; }
}
public class Product
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long ID { get; set; }
public string Name { get; set; }
public PriceDetail Price { get; set; }
public ICollection<Update> Updates { get; set; }
}
public class Rule
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long ID { get; set; }
public string Name { get; set; }
public ICollection<Condition> Conditions { get; set; }
public ICollection<Update> Updates { get; set; }
}
There are multiple ways of handling auditing logic.
Do you anticipate storing update history for every table? If it's going to be limited to a few tables, your design might work fine. If however, you want to update many tables, you might want to try out the options below.
Include 3 tables (Products, Updates and ProductUpdates). The Products tables will always have the latest data. The Updates tables will get a new row capturing the updated timestamp every time an entry in Products is updated. The ProductUpdates will have a foreign key to the Updates table and will have the old row from the Products table. This way you know exactly what the row looked at any point of time. Extending it to any other table X will require adding XUpdates table. But you wouldn't have the unnecessary 50 foreign keys that you mentioned.
Another option would be to have IsActive, UpdatedBy, UpdatedTimestamp, etc... columns in the tables that will be updated. Every time, you update a row, you mark it as inactive and insert a new row with the latest data. You can store the reason and rule columns also if needed.
You can also redesign your entities in such a way that their primary key is a foreign key to your updates table. This way you will eliminate the inelegance of all previous solutions. Every time you update, you will insert a row in the Updates table and use the generated Id as the primary key of a new row in your products table.
Entity Framework can help you in automating the process laid out in points 3 and 4. The basic idea would be to intercept the Save requests for updates and force an update and insert instead.
Lastly, you might also be able to use CLR triggers to have the audit functionality you want.
Each solution has its pros and cons. The best solution for you would depend upon your specific use case.

Where to create MySql tables ServiceStack & OrmLite

I am just wondering about when and where tables should be created for a persisted application. I have registered my database connection factory in Global.asax.cs:
container.Register<IDbConnectionFactory>(new OrmLiteConnectionFactory(conn, MySqlDialectProvider.Instance));
I also understand that I need to use the OrmLite API to create tables from the classes I have defined. So for example to create my User class:
public class User
{
[AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
[Index(Unique = true)]
public string Email { get; set; }
public string Country { get; set; }
public string passwordHash { get; set; }
public DateTime Dob { get; set; }
public Sex Sex { get; set; }
public DateTime CreatedOn { get; set; }
public Active Active { get; set; }
}
I would execute the following:
Db.CreateTable<User>(false);
I have a lot of tables that need to be created. Should I create a separate class that first created all my tables like this or execute that in each rest call to UserService.
Also is it possible to create all my tables directly in my database, naming each table with its corresponding class, and then Orm would match classes to existing tables automatically?
Sorry this has me a bit confused. Thanks for any help you can give me.
I would create them in the AppHost.Configure() which is only run by a single main thread on Startup that's guaranteed to complete before any requests are served.
If you wanted to you can automate this somewhat by using reflection to find all the types that need to be created and calling the non-generic API versions:
db.CreateTable(overwrite:false, typeof(Table1));
db.CreateTable(overwrite:false, new[] { typeof(Table1), typeof(Table2, etc });
is it possible to create all my tables directly in my database, naming each table with its corresponding class, and then Orm would match classes to existing tables automatically?
You don't have to use OrmLite to create tables. If the table(s) already exist in your MySQL database (or you want to create using MySQL interface) you will be able to access them as long as the class name is the same as the table name. If table names don't match the class names, use the Alias attribute
[Alias("Users")] //If table name is Users
public class User
{
public int Id {get;set;}
}
I wouldn't create the tables in your services. Generally, I would do it in AppHost.Configure method which is run when the application starts. Doing this will attempt to create the tables every time your application is started (which could be once a day - see here) so you might want to set a flag in a config file to do a check for creating the tables.

Azure table storage inverse relationship

I am using azure table storage (Note: NOT Azure SQL) and I have the following situation:
In my application I have a number of organisations that 'invite' users, and on the invite there is an associated 'Role' and 'Expiry'. Once the organisation has invited a user I want the org to see the list of users that they have invited, and I want the user to see a list of organisations that they have been invited to.
I think in my application and this case, that there would be low numbers (ie an org would only invite a few users and a user will generally only be invited by one org). However is there a general pattern that people use to deal with this situation even with very large numbers?
I have three approaches that I currently use, depending on my needs:
Transactional
I store the forward and inverse relationship on the same partition... this means that EVERY entity is on the same partition (ie this method is rate limited by a single partition), but it means you can use a batch transaction to insert the forward and inverse relationship at the same time which means that you know they will always be correct.
public class OrganisationInvite : TableEntity
{
// Partition Id - string.Empty
// Row Id - "Invite_" + OrangisationId + "_" + UserId
public string Role { get; set; }
public DateTime Expiry { get; set; }
}
public class OrganisationRequest : TableEntity
{
// Partition Id - string.Empty
// Row Id - "Request_" + UserId + "_" + OrganisationId
public string Role { get; set; }
public DateTime Expiry { get; set; }
}
To query I use a t.RowKey.StartsWith("Request_...") or t.RowKey.StartsWith("Invite_...") depending on whether I want to get a list of a user/org invites.
I guess this is best used when the data is very critical.
Eventual Consistency
I give both tables all the properties but they live on different partitions, this gives you awesome scalability but you loose the transaction. I use a messaging queue to update the inverse relationship to match the forward relationship, so eventually the data will match. (But for a while it may not).
// Assume both in the same table, thus the prefix on partition
public class OrganisationInvite : TableEntity
{
// Partition Id - "Invite_" + OrangisationId
// Row Id - UserId
public string Role { get; set; }
public DateTime Expiry { get; set; }
}
public class OrganisationRequest : TableEntity
{
// Partition Id - "Request_" + UserId
// Row Id - OrganisationId
public string Role { get; set; }
public DateTime Expiry { get; set; }
}
To query I use a t.PatitionKey == "Request_..." or t.PatitionKey == "Invite_..." depending on whether I want to get a list of a user/org invites. Perhaps you would consider one of these the 'source of truth' so when a user does accept the invite you would look up the 'source of truth' and give the user that role etc.
This is the most scalable solution, and especially makes sense if you are using caching on top of it.
Source of truth
In this case I only give the properties on one entity, and only have the keys of the inverse relationship on the other. You would add the entities to the list that is longest or is queried the most... in this case I would say it is the invites for an org. Like the eventual consistency method you would queue the inverse relationship to add the inverse entity. This method gives you complete data consistency except for when you add a new relationship (as there is a bit of time before the inverse relationship is created), and is highly scalable - there is a higher cost to read the inverse list though.
// Assume both in the same table, thus the prefix on partition
public class OrganisationInvite : TableEntity
{
// Partition Id - "Invite_" + OrangisationId
// Row Id - UserId
public string Role { get; set; }
public DateTime Expiry { get; set; }
}
public class OrganisationRequest : TableEntity
{
// Partition Id - "Request_" + UserId
// Row Id - OrganisationId
}
You can trivially query the forward relationship using t.PatitionKey == "Invite_...". The inverse relationship is not trivial though. You have to query using t.PatitionKey == "Request_..." and create n number of parallel calls to get each item's data forward data (In this case to use the org id found in the inverse relationship's RowKey). If the item does not exist then you do not add it to your final list. This ensures that if the org changes its role for example the user will see this change on the next hit.
I think this method is useful if the inverse relationship is used rarely and it is critical that the data is up to date (I'm thinking user permissions etc?)

Order the Columns, while creating DB by Entity Framework 4.1. with fluent API

I want have an order of my database table columns after creating DB by entity framework 4.1. in the following way:
1) PK
2) all foreign key columns
3) all complex types columns
4) all Other Columns
The problem is that it is no possibility to set the Order for foreign key's by fluent API, like for example HasColumnOrder for primitive properties.(all foreign key columns are the last columns)
Are there some ideas?
Thanks
Chris
I know this is an old thread, but I thought I would actually answer it. I agree, the column order in the DB makes no difference. Except for when you are in the DB searching on data, then it can be useful to have the logical/useful fields first.
The answer is with the .HasColumnOrder(x) method. Just put in a zero-based number of what order you want the field to be in. See an example here: http://hanksnh.wordpress.com/2011/04/08/inheritance-with-entity-framework-4-1/
If you want to set order for foreign key columns you must expose them as properties (use foreign key association instead of independent association). Btw. order of columns in database table doesn't matter. Only order of columns in a key matters and it is why there is no brother support for this.
I have solved the problem with foreign key columns order in the database while using independent association with the help of EF migrations.
Disable automatic migrations and create initial migration for your data model.
For model class:
public class Session
{
public int? Id { get; set; }
public Track Track { get; set; }
public Car Car { get; set; }
public int Event { get; set; }
public DateTime Date { get; set; }
public string Name { get; set; }
}
the migration code will be generated:
CreateTable("dbo.Sessions", c => new
{
Id = c.Int(nullable: false, identity: true),
Event = c.Int(nullable: false),
Date = c.DateTime(nullable: false),
Name = c.String(nullable: false, maxLength: 64),
Car = c.Int(nullable: false),
Track = c.Int(nullable: false),
}) ...
Now just reorder the foreign key columns (Car, Track) by moving them up. When you create new database and open the table, the column order will be like expected.
If you are looking for column order, I think its pretty easy. In your DbContext class, override OnModelCreating. Then grab modelBuilder, and from it pull out EntityTypeConfiguration. Then using it configure the order as follows.
public class AppDbContext : IdentityDbContext<AppUser, AppRole, int, AppUserLogin, AppUserRole, AppUserClaim>
{
public AppDbContext() : base("AvbhHis")
{
}
public DbSet<PatientCategory> Product { get; set; }
public DbSet<LookupBase> LookupBase { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder
.Entity<PatientCategoryLookup>()
.Map<PatientCategoryLookup>(m =>
{
m.ToTable("LookupPatientCategory");
m.MapInheritedProperties();
});
EntityTypeConfiguration<PatientCategoryLookup> config = modelBuilder.Entity<PatientCategoryLookup>();
config.Property(e => e.Id).HasColumnOrder(0);
config.Property(e => e.PatientCatgCode).HasColumnOrder(1);
config.Property(e => e.PatientCatgName).HasColumnOrder(2);
config.Property(e => e.Description).HasColumnOrder(3);
config.Property(e => e.ModifiedTime).HasColumnOrder(4);
config.Property(e => e.History).HasColumnOrder(5);
base.OnModelCreating(modelBuilder);
}
}
And then finally you need to add migration and then update database.

Resources