How do you fashion projections in SubSonic 2.2? Basically I wish to return columns from two tables that are joined.
My personal preference for how to do this is to create a SQL View which joins the table and have subsonic generate an object that maps to it.
You can also use ExecuteTypedList with a custom defined object for example:
public class TestObject{
int Column1 { get; set; }
int Column2 { get; set; }
}
List<TestObject> testObjects = DB.Select(Table1.Columns.Column1, Table2.Columns.Column2)
.From(Table1.Schema)
.InnerJoin(Table2.Schema)
.ExecuteTypedList<TestObject>();
Related
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.
I have model generated by ADO Entity Data Model like:
public partial class Category
{
public Category()
{
}
public int CategoryId { get; set; }
public string Name { get; set; }
}
now I have added one property
public partial class Category
{
public int EventsCount { get; set; }
}
Now I am trying to map by: //this is working Query
List<Category> retVal = db.Database.SqlQuery<Category>(
//retVal = db.Categories.SqlQuery(
#"SELECT c2.CategoryId,c2.Name,c1.EventsCount AS EventsCount FROM (
SELECT c.CategoryId, COUNT(c.CategoryId) AS EventsCount FROM Category c
JOIN EventCategory ec ON ec.CategoryId = c.CategoryId
JOIN (SELECT * FROM EVENT WHERE EventDateTime > DATEADD(D, 0, DATEDIFF(D, 0, GETDATE()))) e ON e.EventId = ec.EventId
WHERE c.ImportedFrom IS NULL
GROUP BY c.CategoryId) c1
join Category c2 ON c1.CategoryId = c2.CategoryId").ToList();
Actual Data I get executing raw sql on Management Studio
but EventCounts is always 0 with Entity Framework mapping ,
but If I map model with different Model having EventsCount , then it is mapped.
like:
public partial class Category
{
public Category()
{
}
public int CategoryId { get; set; }
public string Name { get; set; }
public int EventsCount { get; set; }
}
now there are mapped all columns,, Any idea here, why Entity framework in not mapping partial model?
I have not got exact answer for this,
But I got solution by inheriting model than making partial class.
As EntityFramework mapp data with help of reflection and reflection cannot deal with property with partial class
check this
.NET reflection: how to get properties defined on partial class
so what I did is:
first make anther class with inheriting class generated by EF, and add property that we want.
public partial class CategoryEx:Category
{
public int EventsCount { get; set; }
}
and definitely,
List<CategoryEx> retVal = db.Database.SqlQuery<Category>(
//retVal = db.Categories.SqlQuery(
#"SELECT c2.CategoryId,c2.Name,c1.EventsCount AS EventsCount FROM (
SELECT c.CategoryId, COUNT(c.CategoryId) AS EventsCount FROM Category c
JOIN EventCategory ec ON ec.CategoryId = c.CategoryId
JOIN (SELECT * FROM EVENT WHERE EventDateTime > DATEADD(D, 0, DATEDIFF(D, 0, GETDATE()))) e ON e.EventId = ec.EventId
WHERE c.ImportedFrom IS NULL
GROUP BY c.CategoryId) c1
join Category c2 ON c1.CategoryId = c2.CategoryId").ToList();
now EventsCount is there.
I have no idea but it may be helpful for somebody.
As far as my interpretation is concerned you are trying to bind more data then it is there in the class. You can bind only event count rather then trying to bind c2.CategoryId, c2.Name using select query.
I am not sure but i think that this should work.
I came across the same issue . It seems to be a bug in EF. For me the solution was the excellent Dapper library. It's just a bunch of extension methods so it can work side by side with EF.
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();
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.
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.