How do you model a simple composition relationship - c#

Can someone help me understand how best to model a composition relationship?
If for instance I have a student whom can have many schedules, I would create roughly:
class Student
{
prop long Pk { get; set; }
prop string Name { get; set; }
prop List<Schedule> Schedules { get; set; }
}
class Schedule
{
prop string Semester { get; set; }
prop List<Course> Courses{ get; set; }
}
Somewhere down the line I may have a Schedule object, and will wish to identify which student it belongs to. I want to be able to write Schedule.Student.Name, and receive the student's name in return. Do I add a Student property to my Schedule object as well?
My application has been passing a Student Pk to my Schedule object in order to do CRUD functionality. I'm keeping the Student PK as a private variable in order to keep a handle on it if I need it.
As my application becomes more complex, I'm finding it hard to maintain what I've been doing. What are your suggestions for me? What else can I consult (books/links) to get a refresher and better handle on these fundamentals?

"I want to be able to write Schedule.Student.Name, and receive the student's name in return. Do I add a Student property to my Schedule object as well?" Yes.
What you are describing (supporting both foreign keys for lookup and object references for easy navigation of the object graph) sounds like a really good match for an object-relational mapper (ORM). A good ORM will automatically load the associated object/objects for you using the FK/PK (e.g. if the Schedule has a StudentPK field then the mapper will handle loading/mapping of the Student property for you). There are many products of this type: you can use built-in .NET frameworks such as the Entity Framework, open-source ones such as NHibernate or commercial products such as LightSpeed, LLBLGen, EntitySpaces or OpenAccess (disclosure: I work for a company that makes a commercial ORM). Google for ORM or object-relational mapper, or check Wikipedia, for an overview of the kind of thing I'm describing.

Related

Entity design when principal entity state is an aggregate of its dependant entities

Let's define Term as a principal entity and Course as a one to many dependant relationship.
public class Term
{
public int Id { get; set; }
public List<Course> Courses { get; set; } = new List<Course>();
}
public class Course
{
public int Id { get; set; }
public DateTime EndDate { get; set; }
}
A common query criteria for our Term entity is to check whether all of the courses are finished or not and by that we deem the Term as finished or not too, and this implicit state can show itself in a lot of places in our bussiness logic, simple queries to populate view models, etc.
Using ORMs like EntityFramework Core this query can popup in a lot of places.
Terms.Where(t=>t.Courses.All(c=>c.EndTime > DateTime.Now))
Terms.Count(t=>t.Courses.All(c=>c.EndTime > DateTime.Now))
Other examples of this that come to mind are a product and its current inventory count, posts that only contain unconfirmed comments, etc.
What can we consider as best practice if we are to capture these implicit states and make them directly accessible in our principal entity without the need to rehydrate our dependant entity from the database too?
Some solutions that come to mind:
Using a computed column to do a subquery and map it to a property on the principal entity e.g. Term.IsFinished
Defining a normal property on our entity and use a scheduling solution to update its value on predetermined timestamps which is not acceptable in a lot of cases due to inconsistency in different intervals, or use domain events and react upon them to update the property on the principal entity
Create a view, with the two tables joined and aggregated per principal entity.
Use the view directly in Entity Framework instead of the base table.
For bonus points:
In SQL Server you can create a clustered index on the view, and it will be automatically maintained for you. Oracle has a similar concept.
In other RDBMSs, you would need to create a separate table, and maintain it yourself with triggers.

SqliteNetExtensions is it possible to ignore a specified child when calling InsertOrReplaceWithChildren()?

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.

How to insert an ObservableCollection property to a local sqlite-net db?

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.

Best strategies when working with micro ORM?

I started using PetaPOCO and Dapper and they both have their own limitations. But on the contrary, they are so lightning fast than Entity Framework that I tend to let go the limitations of it.
My question is: Is there any ORM which lets us define one-to-many, many-to-one and many-to-many relationships concretely? Both Dapper.Net and PetaPOCO they kind of implement hack-ish way to fake these relationship and moreover they don't even scale very well when you may have 5-6 joins. If there isn't a single micro ORM that can let us deal with it, then my 2nd question is should I let go the fact that these micro ORMs aren't that good in defining relationships and create a new POCO entity for every single type of query that I would be executing that includes these types of multi joins? Can this scale well?
I hope I am clear with my question. If not, let me know.
I generally follow these steps.
I create my viewmodel in such a way that represents the exact data and format I want to display in a view.
I query straight from the database via PetaPoco on to my view models.
In my branch I have a
T SingleInto<T>(T instance, string sql, params object[] args);
method which takes an existing object and can map columns directly on to it matched by name. This works brilliantly for this scenario.
My branch can be found here if needed.
https://github.com/schotime/petapoco/
they don't even scale very well when you may have 5-6 joins
Yes, they don't, but that is a good thing, because when the system you will be building starts to get complex, you are free to do the joins you want, without performance penalties or headaches.
Yes, I miss when I don't needed to write all this JOINS with Linq2SQL, but then I created a simple tool to write the common joins so I get the basic SQL for any entity and then I can build from there.
Example:
[TableName("Product")]
[PrimaryKey("ProductID")]
[ExplicitColumns]
public class Product {
[PetaPoco.Column("ProductID")]
public int ProductID { get; set; }
[PetaPoco.Column("Name")]
[Display(Name = "Name")]
[Required]
[StringLength(50)]
public String Name { get; set; }
...
...
[PetaPoco.Column("ProductTypeID")]
[Display(Name = "ProductType")]
public int ProductTypeID { get; set; }
[ResultColumn]
public string ProductType { get; set; }
...
...
public static Product SingleOrDefault(int id) {
var sql = BaseQuery();
sql.Append("WHERE Product.ProductID = #0", id);
return DbHelper.CurrentDb().SingleOrDefault<Product>(sql);
}
public static PetaPoco.Sql BaseQuery(int TopN = 0) {
var sql = PetaPoco.Sql.Builder;
sql.AppendSelectTop(TopN);
sql.Append("Product.*, ProductType.Name as ProductType");
sql.Append("FROM Product");
sql.Append(" INNER JOIN ProductType ON Product.ProductoTypeID = ProductType.ProductTypeID");
return sql;
}
Would QueryFirst help here? You get the speed of micro orms, with the added comfort of every-error-a-compile-time-error, plus intellisense both for your queries and their output. You define your joins in SQL as god intended. If typing out join conditions is really bugging you, DBForge might be the answer, and because you're working in SQL, these tools are compatible, and you're not locked in.

Database model to object oriented design?

How would I design classes say in c# to represents a database model?
Given the following tables and fields for a database,
Table: Employee
Pk EmpID
Lname
Fname
Adress
Fk DeptID
Table: Department
Pk DeptID
DeptName
Location
Ok so now I want to make 2 classes in C#, one for Employee and one for Department. The part I get hung up on is the foreign keys. Should I use the foreign keys in my design for the objects, or should I put a reference in my Employee class of the Department,or should I put a list of employee references in my Department class,or should I do both? I know if I use foreign keys, it will be less efficient because I will have to search through a list of primary keys that match the foreign key but I probably should include them in the design anyway.
Don't use "foreign keys" in your objects. Use references; each Department should have a list of Employees. Depending on whether or not you have a need to backreference from Employee to their Department, make the determination as to whether Employee will have a reference to Department.
Elaboration on #Paul Sonier answer...
P.S. I'm using business layer, business classes in a general sense, not as jargon of some particular technical design pattern.
The specific problems of using database keys
Using database keys is going to cause an explosion of coding overhead to keep objects and the database in synch. As the need to add, change, delete objects happens (via user GUI) you'll be jumping through hoops like crazy. How would you create a child object when the parent object does not exist yet in the database? Imagine trying to do this with any N-level data structure.
Always design business classes without regard to data storage
Business layer classes should faithfully reflect the business rules, jargon, concepts, and context. Polluting this "idea space" with non-business stuff with details about storing or displaying data is bad in the long run. Hear me now and believe me later.
Business classes based on some particular database table layout (and it's keys, etc.) is going to make it disastrously difficult to write code for validating rules, creating proper state of those objects, and so on. This is on top of the problem of keeping the object IDs in synch w/ the database.
Maximize Decoupling of Business layer and Data layer
The example shown in your question is a tempting deception. Some of your business classes may map very well to your database design. And consequently the primary and foreign keys may seem to fit as well.
BUT in any non-trivial application the database model will deviate. If not now, later. It will deviate for the purposes of database integrity, efficiency, and speed. And what does this have to do with the business model? Nothing.
Indicators that you're doing things right
You can instantiate a business object without an existing database
Each object can reference it's "children" without requiring special keys created outside the business class model.
Each business object on its own can validate, enforce, flag, etc. all of it's own rules, even trivial ones like "can't be blank". Business rule validation for composite classes/objects is class design & analysis activity - not database design activity.
First, if possible I would suggest using a tool like NHibernate, the Entity Framework, or Linq to SQL to do the object to relational mapping for you. But, if you don't want to do that, I'd probably design my object model like this:
public class Employee
{
public int Id { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public Address Address { get; set; }
public Department Department { get; set; }
}
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
public Address Location { get; set; }
public ICollection<Employee> Employees { get; set; }
}
I don't want to oversimplify but if you have navigation properties from Employee => Department or Department => Employee is pretty specific to the needs of your application.
However, as a rule of thumb, I tend to put navigation properties from the top of the heirarchy down. That means I would have Department.Employees but not Employee.Departments.
Again, this is specific to you, but it seems pretty unlikely that you would ever need to get the Department object from every single Employee. So, lookup with a key inside the Employee class something like this:
class Employee {
public int[] DepartmentIds { get; set; }
public List<Department> Departments {
get {
return YourStaticReference.DepartmentList
.Where(x => this.DepartmentIds.Contains(x.DepartmentId));
}
}
}
See? Best of luck!

Categories

Resources