ORMers,how are you going to deal with this in the ORM style? - orm

We are modifying our post on stackoverflow.
And we only changed the tags part,removed tag1,tag2 and added tag3,tag4.
After pressing the Post Your Question button,these things should be done:
reduced the count column for tag1,tag2 by 1
delete the relation between the post and tag1,tag2
if tag3,tag4 already exists,increase the count column of the two by 1;otherwise,insert them to the tags table with count value 1
add the relation between the post and tag3,tag4
Let's take a deep breath and that's all!
I want to see which ORM can approach this most easily/performant no matter it's written in PHP/Java/C/.Net or any language else,because the ideas are similar across languages!

In DataObjects.Net it will look like this. There is now any mapping files because database schema is automatically generated by ORM, including auxiliary table for question-tag relation.
Tag class:
[HierachyRoot]
public class Tag : Entity
{
[Field, Key]
public int Id { get; private set; }
[Field(Length = 100, Indexed = true)]
public string Name { get; private set; }
[Field]
public int QuestionsCount { get; set; }
public Tag(string name)
{
Name = name;
}
}
Question class:
[HierachyRoot]
public class Question : Entity
{
[Field, Key]
public int Id { get; private set; }
[Field]
public EntitySet<Tag> Tags { get; private set; }
// Business methods (can be placed in separate service class)
public void AddTag(string name)
{
var tag = Query.All<Tag>().SingleOrDefault(t => t.Name == name);
if (tag==null)
tag = new Tag(name) { QuestionsCount = 1 }
else
tag.QuestionsCount++;
Tags.Add(tag);
}
public void RemoveTag(string name)
{
var tag = Query.All<Tag>.Single(t => t.Name == name);
tag.QuestionsCount--;
Tags.Remove(tag);
}
}
Application code:
using (Session.Open())
using (var transactionScope = Transaction.Open())
{
var question = Query.Single<Question>(questionId);
question.RemoveTag("tag1");
question.RemoveTag("tag2");
question.AddTag("tag3");
question.AddTag("tag4");
transactionScope.Complete();
}

Related

Get actual model type from dynamic type

I have three tables in my database (Student, Course, All). When I add any data in Student & Course table, the data also gets added in All table.
So, I'm using dynamic type data to pass Student & Course type data to get saved in All table.
public IActionResult Add(Student model)
{ ...
bool studentData = _studentService.Add(model); //saving in Student table
bool allData= _allService.AddAll(model); // passing 'Student' type data
...
}
In the All service, I've a function like-
public bool AddAll(dynamic model) // 'Student' type data passed & received as dynamic
{...}
Now, I need the details about Student model type (table name, total data found etc.).
Is there any way to get it? And is it possible to get the Student or Course model type info if I use dynamic data type?
Any suggestion or help will be much appreciated :) Thanks in advance!
If you want to get model type,you can use model.GetType(),and you can use model.GetType().Name to get model type Name,here is a demo:
Model:
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
}
public class Course
{
public int CourseId { get; set; }
public string CourseName { get; set; }
}
Action:
public void Add(Student model)
{
//Student s = new Student { StudentId=1, StudentName="s1" };
Course c = new Course { CourseId=1,CourseName="c1" };
bool allData = AddAll(c);
}
public bool AddAll(dynamic model)
{
var type = model.GetType();
var typeName = type.Name;
return true;
}
result:
Is this example demonstrate what you trying to do ?
// Some dummy classes
public class Student
{
public string Name { get; set; }
public Student(string name)
{
Name = name;
}
}
public class Course
{
public string Title { get; set; }
public Course(string title)
{
Title = title;
}
}
// put the method somewhere
private string TypeCasting(dynamic myContent)
{
if (myContent is Student littleStudent)
{
return littleStudent.Name;
}
if (myContent is Course someLovelyCourse)
{
return someLovelyCourse.Title;
}
return string.Empty;
}
// Example using
var student = TypeCasting(new Student("fossil"));
var course = TypeCasting(new Course("type casting"));

DDD shared entity between two aggregate roots

I'm working with two different aggregate roots: Post and Question. Both of them have a Category.
So far I have implemented it as a shared entity (which I'm not sure if is a correct design in DDD).
public class Post
{
public Guid Id { get; private set; }
public Category Category { get; private set; }
public string Title { get; private set; }
public string Body { get; private set; }
}
public class Question
{
public Guid Id { get; private set; }
public Category Category { get; private set; }
public string Title { get; private set; }
public string Body { get; private set; }
}
public class Category
{
public int Id { get; private set; }
public string Name { get; private set; }
public string Key { get; private set; }
}
Note: I'm aware I'm falling into primitive obsession anti-pattern, and I have plans on refactor the primitives into ValueObjects.
After read this post DDD: Share entity with multiple aggregate roots I'm thinking that maybe I should convert the Category in a ValueObject (with multiple fields).
In theory Category could be an Entity with its own lifecycle, but reality is that I don't really add/remove/update categories.
Is it possible to use a shared Entity on DDD? Or I better rather use a ValueObject?
Lets deal with one aggregate first: Post
Now to answer your question:
Is it possible to use a shared Entity on DDD? Or I better rather use a ValueObject?
It depends on what you will do with Category.
Scenario 1:
You have a feature(or page) in your application to show all posts of a category. I would go with the following design:
public class Category
{
public int Id { get; set; }
//this is my in-memory database. Use repository and service to adjust yours
public static List<Post> Posts;
public Category()
{
Posts = new List<Post>();
}
public void AddPost(Guid id, string title, string body)
{
var post = new Post(id, title, body, this.Id);
//saving the post into in-memory. Perhaps you can check some business logic inside Post entity
Posts.Add(post);
}
// You can retrieve all posts of a single category
public IEnumerable<Post> GetAllPosts()
{
return Posts.Where(x => x.CategoryId == this.Id);
}
}
public class Post
{
public Guid Id { get; private set; }
public string Title { get; private set; }
public string Body { get; private set; }
public int CategoryId { get; private set; }
public Post(Guid id)
{
Id = id;
}
public Post(Guid id, string title, string body, int categoryId)
{
//I prefer to pass guid into domain from external services.
//Using this way, your service will have the id to return to upper layers.
//Alternatively you can create new guid here on your own
Id = id;
Title = title;
Body = body;
CategoryId = categoryId;
}
// you can retrieve a post detail
public Post GetPost()
{
return Category.Posts.FirstOrDefault(x => x.Id == this.Id);
}
}
I can see only one aggregate root in this scenario: Category.
Scenario 2:
You have posts page, from there users can view detail post. Additionally, every post has a category which will be shown somewhere on that detailed page. You can have following simple design:
public class Post
{
public Guid Id { get; private set; }
public string Title { get; private set; }
public string Body { get; private set; }
public string CatKey { get; private set; }
public Post(Guid id)
{
Id = id;
}
public Post(Guid id, string title, string body, string catKey)
{
//I prefer to pass guid into domain from external services.
//Using this way, your service will have the id to return to upper layers.
//Alternatively you can create new guid here on your own
Id = id;
Title = title;
Body = body;
//I don't even bother with category id. This is a simple value object, you can store all of your categories
//into a hashtable of key-value
CatKey = catKey;
}
// you can retrieve a post detail
public Post GetPost()
{
//get your post detail from repo
}
}
Hope you can make your decision now.
The main question of Entity vs ValueObject is would two instances of the Category with the same values need to be tracked differently? The classic example is a dollar bill - in most instances, the serial number (ID) doesn't matter, and one dollar is the same as another (ValueObject). If your domain is collecting rare bills, though, that would change.
I'd suspect not in your case, since it appears Category is really just comprised of the name and key. If the Category of a Post changes, do you need to track what the Category previous was?

Entity Framework Core storing many to many relationship from multiple feeds of data

How do you implement entity framework core classes properly to support a many to many relationship between two classes but the array/data of those classes and relationships is coming from 2 or more data sources.
That is to say if we had a simple relationship such as:
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class PostTag
{
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
}
Our server is going to get an array of Posts, Tags, and any of their relationships from two more or data sources via a web api. So if we were simply to try to take the data directly and serialize it back into our database there would be collisions with the Id Key's given the 2 or more different sources. What is the proper way to store difference sources of the same class structure and also to not lose the relationship information? thank you
What you are missing a conversion layer. Let me explain.
Your post object stored in the database has to have the following structure:
Post Table
+------------+----------------+-------+----------+
| PostId | ExternalPostId | Title | Content |
+------------+----------------+-------+----------+
PostId - This is the primary key within your own table. Auto-generated, required.
ExternalPostId - this is the PostId as it arrives from the API.
Title - this is the title as it arrives from the API
Content - this is the content as it arrives from the API.
Tag table
+--------+---------------+-------------+-------------+
| TagId | ExternalTagId | OtherField1 | OtherField2 |
+--------+---------------+-------------+-------------+
TagId - This is the primary key of your own Tag table. Autogenerated, required.
ExternalTagId - this is the TagId as it arrives from the API
OtherField1, OtherField2 - whatever other fields arrive with the tag from the API.
Join Table
+------------+-------+
| PostId | TagId |
+------------+-------+
PostId, TagId - Composite Primary key
PostId - foreign key, required, non-auto-numbered referencing the Post table.
TagId - foreign key, required, non-auto-numbered referencing the Tag table.
At that point your entities will look like this:
Post Enity
[Table("Post")]
public class DbPost {
[Key]
[Column("PostId")]
public int Id { get; set; }
[Column("ExternalPostId")]
public int ExternalId { get; set; }
[Column("Title")]
public string Title { get; set; }
[Column("Content")]
public string Content { get; set; }
public IList<PostTag> PostTags { get; set; }
}
Tag entity:
[Table("Tag")
public class DbTag
{
[Key]
[Column("TagId")]
public int Id { get; set; }
[Column("ExternalTagId")]
public string ExternalId { get; set; }
public IList<PostTag> PostTags { get; set; }
}
PostTag Entity
This entity stays the same. The difference here is that PostId is mapped to the Id property of the Post entity, which is your own primary key of your own Post table. In a similar fashion the TagId is mapped to the Id property of the Tag table, which is also your own primary key, of your own table.
public class DbPostTag
{
public int PostId { get; set; }
public Post Post { get; set; }
public int TagId { get; set; }
public Tag Tag { get; set; }
}
Finally, your domain context:
public class Database : DbContext {
public virtual DbSet<DbPost> Posts { get; set; }
public virtual DbSet<DbTag> Tags { get; set; }
public virtual DbSet<DbPostTag> PostTags { get; set; }
...
}
When you insert a post from the API you need to create a translation between the post from the API to the post entity in your database. You can do so via an extension method or a method that translates this for you:
public static class ApiObjectExtensions {
public static DbPost ToDbPost(this Post post){
var dbPost = new DbPost(){
ExternalId = post.PostId,
Title = post.Title,
Content = post.Content,
PostTags = new List<DbPostTags>()
};
}
public static DbTag ToDbTag(this Tag tag){
return new DbTag(){
ExternalId = tag.Id,
PostTags = new List<DbPostTags>()
};
}
}
So when you are inserting the data in the domain context you simply have to convert the corresponding entities. This code assumes that you really have the object graph described above and your post has a bunch of post tags, and the each post tag has a bunch of tags.
foreach(var post in posts){
var dbPost = post.ToDbPost();
if(post.PostTags != null && post.PostTags.Any()){
foreach(var postTag in post.PostTags){
if(postTag.Tag != null){
var dbTag = postTag.Tag.ToDbTag();
var dbPostTag = new DbPostTag(){
Post = dbPost,
Tag = dbTag
};
dbPost.PostTags.Add(dbPostTag);
}
}
}
Database.DbPosts.Add(dbPost);
}
Database.SaveChanges();
If you are receiving the posts, the post tags, and the tags in separate calls than your insert operation will be a bit different:
var insertedPosts = new List<DbPost>();
var insertedTags = new List<DbTag>();
foreach(var post in posts){
var dbPost = post.ToDbPost();
Database.Posts.Add(dbPost);
insertedPosts.Add(dbPost);
}
foreach(var tag in tags){
var dbTag = tag.ToDbTag();
Database.Tags.Add(dbTag);
insertedTags.Add(dbTag);
}
Database.SaveChanges();
This will write all db post and db tag entities to the db and assign their primary keys.
The next step would be to link the two together.
foreach(var postTag in postTags){
var dbPost = insertedPosts.FirstOrDefault(p => p.ExternalId = postTag.PostId);
var dbTag = insertedTags.FirstOrDefault(t => t.ExternalId = postTag.TagId);
if(dbPost != null && dbTag != null){
var dbPostTag = new DbPostTag(){
PostId = dbPost.Id,
Tag = dbTag.Id
};
Database.PostTags.Add(dbPostTag);
}
}
Database.SaveChanges();
The last piece is when you retrieve the data back and you want it in the original format.
The following query will return all posts, their linking entities, and their tags:
var dbPosts = this.Database.Posts
.Include( p => p.PostTags )
.ThenInclude(pt => pt.Tag )
.ToList();
var apiPosts = dbPosts.Select(p => p.ToApiPost()).ToList();
To convert the stuff back to the original Post, PostTag, and Tag types you can simply create extension methods as follows:
public static class DbObjectExtensions {
public static Post ToApiPost(this DbPost dbPost){
var post = new Post(){
PostId = dbPost.ExternalId,
Title = dbPost.Title,
Content = dbPost.Content,
PostTags = new List<PostTag>()
};
if(dbPost.PostTags != null) {
foreach(var dbPostTag in dbPost.PostTags){
if(dbPostTag.Tag != null){
var tag = dbPostTag.Tag.ToApiTag();
var postTag = new PostTag(){
PostId = post.PostId,
Post = post,
TagId = tag.TagId,
Tag = tag
};
post.PostTags.Add(postTag);
tag.PostTags.Add(postTag);
}
}
}
return post;
}
public static Tag ToApiTag(this DbTag dbTag){
return new Tag(){
TagId = dbTag.ExternalId
};
}
}

Sorting on nested Id property

Let's say we have a document like this
public class Event
{
public string Id { get; set; }
public EntityDescriptor Venue { get; set; }
// Other properties omitted for simplicity
}
public class EntityDescriptor
{
public string Id { get; set; }
public string Name { get; set; }
}
And an index like this
public class Events : AbstractIndexCreationTask<Event>
{
public Events()
{
Map = items => from e in items
select new
{
Venue_Id = e.Venue.Id,
Venue_Name = e.Venue.Name
};
}
}
When trying to sort on Event.Venue.Id
session.Query<Event, Events>().Take(10).OrderBy(e => e.Venue.Id).ToArray();
the sent request is
/indexes/Events?&pageSize=10&sort=__document_id&SortHint-__document_id=String
Is this by design or a bug?
PS: OrderBy(e => e.Venue.Name) works as expected (sort=Venue_Name).
It's not a bug. __document_id is the special known field containing the ID of the document. It's there regardless of whether you have an .Id property.
edit
I misread your question. This indeed appears to be a bug. I recommend you send a simple repro case to the Raven forum and let them know which RavenDB version you're using.

One-to-Many relationship with ORMLite

The only examples I can find addressing this sort of scenario are pretty old, and I'm wondering what the best way is to do this with the latest version of ORMLite...
Say I have two tables (simplified):
public class Patient
{
[Alias("PatientId")]
[Autoincrement]
public int Id { get; set; }
public string Name { get; set; }
}
public class Insurance
{
[Alias("InsuranceId")]
[Autoincrement]
public int Id { get; set; }
[ForeignKey(typeof("Patient"))]
public int PatientId { get; set; }
public string Policy { get; set; }
public string Level { get; set; }
}
Patients can have multiple Insurance policies at different "levels" (primary, secondary, etc). I understand the concept of blobbing the insurance information as a Dictionary type object and adding it directly to the [Patient] POCO like this:
public class Patient
{
public Patient() {
this.Insurances = new Dictionary<string, Insurance>(); // "string" would be the Level, could be set as an Enum...
}
[Alias("PatientId")]
[Autoincrement]
public int Id { get; set; }
public string Name { get; set; }
public Dictionary<string, Insurance> Insurances { get; set; }
}
public class Insurance
{
public string Policy { get; set; }
}
...but I need the insurance information to exist in the database as a separate table for use in reporting later.
I know I can join those tables in ORMLite, or create a joined View/Stored Proc in SQL to return the data, but it will obviously return multiple rows for the same Patient.
SELECT Pat.Name, Ins.Policy, Ins.Level
FROM Patient AS Pat JOIN
Insurance AS Ins ON Pat.PatientId = Ins.PatientId
(Result)
"Johnny","ABC123","Primary"
"Johnny","987CBA","Secondary"
How can I map that into a single JSON response object?
I'd like to be able to map a GET request to "/patients/1234" to return a JSON object like:
[{
"PatientId":"1234",
"Name":"Johnny",
"Insurances":[
{"Policy":"ABC123","Level":"Primary"},
{"Policy":"987CBA","Level":"Secondary"}
]
}]
I don't have a lot of hope in this being do-able in a single query. Can it be done in two (one on the Patient table, and a second on the Insurance table)? How would the results of each query be added to the same response object in this nested fashion?
Thanks a ton for any help on this!
Update - 4/29/14
Here's where I'm at...In the "Patient" POCO, I have added the following:
public class Patient
{
[Alias("PatientId")]
[Autoincrement]
public int Id { get; set; }
public string Name { get; set; }
[Ignore]
public List<Insurance> Insurances { get; set; } // ADDED
}
Then, when I want to return a patient with multiple Insurances, I do two queries:
var patientResult = dbConn.Select<Patient>("PatientId = " + request.PatientId);
List<Insurance> insurances = new List<Insurance>();
var insuranceResults = dbConn.Select<Insurance>("PatientId = " + patientResult[0].PatientId);
foreach (patientInsurance pi in insuranceResults)
{
insurances.Add(pi);
}
patientResult[0].Insurances = insurances;
patientResult[0].Message = "Success";
return patientResult;
This works! I get nice JSON with nested items for Insurances while maintaining separate related tables in the db.
What I don't like is that this object cannot be passed back and forth to the database. That is, I can't use the same nested object to automatically insert/update both the Patient and InsurancePolicy tables at the same time. If I remove the "[Ignore]" decorator, I get a field in the Patient table called "Insurances" of type varchar(max). No good, right?
I guess I'm going to need to write some additional code for my PUT/POST methods to extract the "Insurances" node from the JSON, iterate over it, and use each Insurance object to update the database? I'm just hoping I'm not re-inventing the wheel here or doing a ton more work than is necessary.
Comments would still be appreciated! Is Mythz on? :-) Thanks...
An alternate more succinct example:
public void Put(CreatePatient request)
{
var patient = new Patient
{
Name = request.Name,
Insurances = request.Insurances.Map(x =>
new Insurance { Policy = i.Policy, Level = i.Level })
};
db.Save<Patient>(patient, references:true);
}
References are here to save the day!
public class Patient
{
[Alias("PatientId")]
[Autoincrement]
public int Id { get; set; }
public string Name { get; set; }
[Reference]
public List<Insurance> Insurances { get; set; }
}
public class Insurance
{
[Alias("InsuranceId")]
[Autoincrement]
public int Id { get; set; }
[ForeignKey(typeof("Patient"))]
public int PatientId { get; set; }
public string Policy { get; set; }
public string Level { get; set; }
}
I can then take a JSON request with a nested "Insurance" array like this:
{
"Name":"Johnny",
"Insurances":[
{"Policy":"ABC123","Level":"Primary"},
{"Policy":"987CBA","Level":"Secondary"}
]
}
...to create a new record and save it like this:
public bool Put(CreatePatient request)
{
List<Insurance> insurances = new List<Insurance>();
foreach (Insurance i in request.Insurances)
{
insurances.Add(new Insurance
{
Policy = i.Policy,
Level = i.Level
});
}
var patient = new Patient
{
Name = request.Name,
Insurances = insurances
};
db.Save<Patient>(patient, references:true);
return true;
}
Bingo! I get the new Patient record, plus 2 new records in the Insurance table with correct foreign key references back to the PatientId that was just created. This is amazing!
First you should define a foreign collection in Patient class. (with get and set methods)
#ForeignCollectionField
private Collection<Insurance> insurances;
When you query for a patient, you can get its insurances by calling getInsurances method.
To convert all into a single json object with arrays inside you can use a json processor. I use Jackson (https://github.com/FasterXML/jackson) and it works very well. Below will give you json object as a string.
new ObjectMapper().writeValueAsString(patientObject);
To correctly map foreign fields you should define jackson references. In your patient class add a managed reference.
#ForeignCollectionField
#JsonManagedReference("InsurancePatient")
private Collection<Insurance> insurances;
In your insurance class add a back reference.
#JsonBackReference("InsurancePatient")
private Patient patient;
Update:
You can use Jackson to generate objects from json string then iterate and update/create database rows.
objectMapper.readValue(jsonString, Patient.class);