I'm really looking for advice here on best practices so I will explain the situation. We have a fairly large application built on top of POCO and EF 4 with a complicated database. While we have been happy with Entity Framework there are definite performance improvements to be made for example with the following scenario (quite simplified).
We have a table called News which has a collection of users that have added it to their favourites and a collection of ratings (1 - 5) by users for example:
public class News
{
public virtual int NewsId;
public virtual string Title;
.......etc....
public virtual ICollection<User> UserFavourites { get; set; }
public virtual ICollection<Rating> Ratings { get; set; }
}
We have written a stored procedure which returns news for a user and allows us to return whether it is a favourite and whether it has already been rated by the user we are requesting the data for and the current rating for News rather than use EF to build this data from the ICollections and we end up with an object like below.
public class NewsDataModel
{
public int NewsId;
public string Title;
.......etc....
public bool IsFavourite { get; set; }
public bool IsRated { get; set; }
public double Rating { get; set; }
}
The stored procedure is much faster and a single database hit rather than EF with Lazy Loading which could be multiple calls but the data returned by the sproc does not match the POCO class for news which is above.
We have been trying to workout the best way to move forward with this as we have a INewsRepository which can either return the entity framework related class or the custom DataModel class we are populating with a stored procedure and ADO.NET. This doesn't feel right and I would appreciate any advice or insight from others experience about the best way to handle these scenarios when you want a single object with data built from multiple tables which would be a lot faster with a sproc than an entity framework call with lazy loading enabled.
Many thanks for any help
There is nothing wrong with a new method on your repository returning instances of NewsDataModel - it is still in the scope of your INewsRepository because it is data class constructed from news information. Otherwise you will have repository for every data model you defined.
Related
Having recently moved to C#/.Net Core from other languages, I got stuck on a problem with EF Core that I couldn't figure out from the documentation and hope you may be able to help. In a way this is related but not identical to my previous question .Net Core [FromBody] JArray to ICollection
My database holds a number of appointments that are rendered on a Syncfusion schedule. Attendees can be invited to these appointments. To facilitate that, a list of users is displayed in the editor and a JSON array of guids is transmitted with any insert or update action.
The User entity itself is not available within the scope of the application, so I'd like to persist only their Guids for each appointment. I had foreseen this structure:
Appointments (Start, End, ..., ´ICollection Attendees´)
Attendee would simply consist of AppointmentsId and Guid -
Since any one Guid can only attend each Appointment once, a composite Key made up of these two attributes appeared to be useful.
Any appointment can have none, one or many associated Guids.
In Code, I have this (abbreviated):
public class Appointment
{
public int Id { get; set; }
public DateTime StartTime { get; set; }
public ICollection<Attendee> AttendeeList { get; set; }
[NotMapped]
public List<Guid> PostedAttendeeList { get; set; } // Contains a list of Guids after an Insert/Update POST action from [FromBody]
}
Attendee would simply be made up of the Appointment Id and a Guid of a user.
public class Attendee
{
public Guid Id { get; set; }
public int AppointmentId { get; set; }
}
Attendee's configuration is this:
public class AttendeeConfiguration : IEntityTypeConfiguration<Attendee>
{
public void Configure(EntityTypeBuilder<Attendee> builder)
{
builder.HasKey(x => new { x.Id, x.AppointmentId });
}
}
After receiving a POST from the schedule, ´PostedAttendeeList´ may be empty or contain one or more Guids.
If it is an existing Appointment, ´AttendeeList´ may be empty or contain one or more Guids.
I'm wondering about a few things:
a) is there a better way to go about persisting this kind of data? I've tried to understand Owned Entity Types but failed to see if that would help me here.
b) if this is indeed an ok way to handle this, how can I make sure that ´AttendeeList´ is identical to ´PostedAttendeeList´ after processing, so that all new entries are added and those not present in ´PostedAttendeeList´ are removed through EF Core?
I'm especially confused about whom's responsibility it is to maintain ´AppointmentId´ - I wanted to keep the property visible but I understand that EF would fill that in when operating within the base property? Ie. that within the class ´Appointment´, a ´AttendeeList.Add(new Attendee() { Id = "1234-abcd-..." }´ would automagically fill in the AppointmentId upon saving?
If you read until here and are confused, please take a moment to remember when you started programming - I'm thoroughly confused and unable to come up with a better question. Even if you cannot help out with an answer, maybe you could help me make the question better. Thank you all very much! Any comment with suggestions will result in an update to my question in order to improve it.
I'm building a mobile app in xamarin that has a lot of relationships between classes. For simplicity consider it to be a "University" app that has the classes: ExamPapers, Students, ExamAnswers.
The ExamPaper class would look like this
public class ExamPapers {
[ManyToMany(typeof(Student_ExamPaper))]
public List<Student> Students { get; set; }
[OneToMany]
public List<ExamAnswers> Files { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<ExamSection> Sections { get; set; }
public string ExamName { get; set; }
[PrimaryKey]
public string Id { get; set; }
}
So at the moment any sqlitenetextension operation (the ones that end with "WithChildren") will interact with all the relationships when I often just want to interact with one at a time. Here are some example scenarios:
A student "Lana" is just granted access to an ExamPaper "Mathematics 101". Now to grant her access I need to load; all other students with access, all the files for the exam, all the sections. Otherwise these relationships get deleted when I call "InsertOrReplaceWithChildren".
I want to find out the first question in an ExamPaper. I call "GetWithChildren(examId)". I now have an object with a lot of information I don't want (e.g. 300 students and 300 ExamAnswers).
Sorry if I missed something relevant in the documentation, but I've read it through a couple times now. https://bitbucket.org/twincoders/sqlite-net-extensions
Thanks.
Answer on your question in title: No. You cannot.
SQLite-Net-Extensions does not provide such flexible API for manipulating related data.
But there is one helpful thing that can be used in specific cases:
You can work with junction tables as simple tables through SQLite-Net methods (methods without *WithChildren postfix) if junction tables has PrimaryKey (Id).
For example if you have any data which you want to get withoud additional (related) data, just simply call Table</*class*/>() method on specific table with Where(/*your condition*/) clause for getting only data that you really need. Then you can save modified data through Update method.
Unfortunately, this thing will not work with relations update (for example, if you want to move one ExamAnswer from ExamPaper to another ExamPaper object) because all SQLite-Net-Extensions attributes inherited from Ignore SQLite-Net attribute which is ignoring in all SQLite-Net operations.
But there is another one workaround (a little hacky), you can specify second class without any SQLite-Net-Extensions attributes and that's provide you to CRUD any field in specific table.
A long time ago I started working on a simple project to learn a bit more about ASP.NET. A bit later I decided to use a database for storage instead of serialization, so I updated my existing models somewhat to try and make them work with Entity Framework code-first. Unfortunately, it seems that these classes are too complex to be converted to database tables.
Here are the models.
Take this part for example:
// Profile.cs
...
public virtual List<Profile> Friends { get; set; }
public virtual List<Community> Subscriptions { get; set; }
public virtual List<Community> Owned { get; set; }
I don't think this is going to work as it's supposed to, with multiple collections of entities of the same type referenced by another entity it's getting messy without a hierarchy-like structure of data.
How can I make these models more EF friendly?
I'm pretty new with ASP.NET MVC, but I know a lot more about PHP. So if I had 2 connected tables in a database, normally I'd connect them with an ID - secondary key.
Example:
Movies:
+ ID
+ Title
+ Description
+ Genre
-- Comments --
+ ID
+ MoviesID
+ Comment
Thus creating a one to many kind of relationship. But I saw that in ASP.NET MVC people would create models which would reference one another:
public class Movie {
// Annotations not included
public int ID {get;set;}
public string Title {get;set;}
public string Description {get;set;}
public string Genre {get;set;}
public List<Comment> Comment {get;set;}
}
public class Comment {
public int ID {get;set;}
public Movie Movie {get;set;}
public string Comment {get;set;}
}
So the parts where one model calls another, how does that looks like in the database, how do you fill those up in the database, how do you pass values of one comment/movie class to a database of the other class when you want to create a new row? (if that makes sense - example would be how to insert a movie object in the database for when you upload a new comment in the database.) Or if at least you could give me some source to read about it, because I found nothing.
Of course another question would be if this is smart to do, or should you just do it the "traditional" way, following the pattern I did at the top?
Hope it's understandable, thanks!
What you are referring to is an ORM what stands for Object-Relational Mapping.
Basically ORM helps you treat tables and relations between them as objects. This approach makes programming much more easier in terms of common language for code and database.
ORM tools are widely used also in PHP(search for Proper, Doctrine). For C# you can refer to NHibernate, Entity Framework or micro-ORMs like Dapper. The example you provided as a .NET approach is similar to your approach in PHP. The only difference is that you explicitely mark one property as foreign key. You could change your example to:
public class Movie {
//Annootations not included
public int ID {get;set;}
public string Title {get;set;}
public string Description {get;set;}
public string Genre {get;set;}
public List<int> CommentIds {get;set;}
}
public class Comment {
public int ID {get;set;}
public int MovieID {get;set;}
public string Comment {get;set;}
}
but this would only load identifiers for related records. When using ORM you can mark property(which in table is an identifier to the another table record) as strong-typed class, what enables you to load all its data from database.
To make long story short - when using ORM you can load whole Movie when fetching Comment from DB, not only its identifier.
Whole process and its configuration depends on ORM tool you are using, you can use mapping attributes(e.g. in Entity Framework), or fluent mappings(when using NHibernate with Fluent NHibernate). Those tools are quite complex(there are many issues to solve - eager/lazy loading, connection management, session management, LINQ to Entities and many many more, it is impossible to explain it on SO :))
I have a quick question about the sqlite-net library which can be found here : https://github.com/praeclarum/sqlite-net.
The thing is I have no idea how collections, and custom objects will be inserted into the database, and how do I convert them back when querying, if needed.
Take this model for example:
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
private string _name; // The name of the subject. i.e "Physics"
private ObservableCollection<Lesson> _lessons;
Preface: I've not used sqlite-net; rather, I spent some time simply reviewing the source code on the github link posted in the question.
From the first page on the sqlite-net github site, there are two bullet points that should help in some high level understanding:
Very simple methods for executing CRUD operations and queries safely (using parameters) and for retrieving the results of those
query in a strongly typed fashion
In other words, sqlite-net will work well with non-complex models; will probably work best with flattened models.
Works with your data model without forcing you to change your classes. (Contains a small reflection-driven ORM layer.)
In other words, sqlite-net will transform/map the result set of the SQL query to your model; again, will probably work best with flattened models.
Looking at the primary source code of SQLite.cs, there is an InsertAll method and a few overloads that will insert a collection.
When querying for data, you should be able to use the Get<T> method and the Table<T> method and there is also an Query<T> method you could take a look at as well. Each should map the results to the type parameter.
Finally, take a look at the examples and tests for a more in-depth look at using the framework.
I've worked quite a bit with SQLite-net in the past few months (including this presentation yesterday)
how collections, and custom objects will be inserted into the database
I think the answer is they won't.
While it is a very capable database and ORM, SQLite-net is targeting lightweight mobile apps. Because of this lightweight focus, the classes used are generally very simple flattened objects like:
public class Course
{
public int CourseId { get; set; }
public string Name { get; set; }
}
public class Lesson
{
public int LessonId { get; set; }
public string Name { get; set; }
public int CourseId { get; set; }
}
If you then need to Join these back together and to handle insertion and deletion of related objects, then that's down to you - the app developer - to handle. There's no auto-tracking of related objects like there is in a larger, more complicated ORM stack.
In practice, I've not found this a problem. I find SQLite-net very useful in my mobile apps.