Why is construction taking a lot of time? - c#

I have classes that I use with EntityFramework:
public partial class BaseDocument
{
public BaseDocument()
{
DocumentLinks = new List<DocumentLink>();
}
public int Id {set;get;}
public virtual List<DocumentLink> DocumentLinks {set;get;}
}
public partial class Payment:BaseDocument
{
}
public partial class Bill:BaseDocument
{
}
public partial class DocumentLink
{
public int Id{set;get;}
public int StartDocId{set;get;}
public int EndDocId{set;get;}
public virtual BaseDocument StartDoc{set;get;}
public virtual BaseDocument EndDoc{set;get;}
}
Now I select document with Linq and want to iterate through list of his DocumentLinks.
var payment = dbContext.Payments.First(t=>t.Id = id);
foreach(var link in payment.DocumentLinks)
{
if (link is Payment)
{
//do something
}
else if (link is Bill)
{
//do something
}
}
And my code works very slowly at the line if (link is Payment). After this line everything works quickly.
What is wrong?

You mean it is slow in the line that is actually executing the database query? Hint - this is why it is slow.
var payment = dbContext.Payments.First(t=>t.Id = id);
I fail to see how the payment includes the DocumentLiks - which means they are lazy loaded. Which means this happens in the foreach. And there you go. Slow.
Include them in the initial query.

Not a direct answer to your question, but a suggestion that you shouldn't type-sniff like this. Polymorphism allows you to ignore the exact type of an object, use it.
Put whatever behavior you need into BaseDocument and remove the is Payment and is Bill:
var payment = dbContext.Payments[id];
foreach(var link in payment.DocumentLiks)
{
link.DoSomething();
}

This may be because of Lazy loading.
In your DBContext configuration specify:
this.Configuration.LazyLoadingEnabled = false;

Related

How to define aggregate in DDD correctly?

I've been reading about DDD and am still confused about aggregate root.
Imagine that I have a situation similar to a blog, where people can create posts and add comments to other posts.
Rules:
-Everybody needs to have an account to add post or comment
-Users are able to delete their own comments only
With that in mind, I would need the following objects:
-Post
-PostComment
-User
So, I created only the Post object as aggregate root and added some business logic to it
public class User : EntityBase
{
public string Name { get; set; }
public string Avatar { get; set; }
}
public class Post : EntityBase, IAggregate
{
public string Title { get; set; }
public string Content { get; set; }
public User Creator { get; set; }
private IList<PostComment> Comments { get; set; }
public void AddComment(PostComment comment)
{
this.Comments.Add(comment);
}
public void DeleteComment(PostComment comment, int userId)
{
if (comment.Creator.Id != userId)
throw new Exception("You cannot delete a comment that is not yours. blablabla");
this.Comments.Add(comment);
}
public IList<PostComment> GetComments()
{
return this.Comments;
}
}
public class PostComment : EntityBase
{
public string Comment { get; set; }
public User Creator { get; set; }
}
Am I doing this correctly? I mean, is the business logic in the right place? Or I should've made PostComment as aggregate root too and added the logic of add/delete in it?
Warning: it's difficult to reason about DDD using toy problems. Especially in your core domain, the point of all of this work is that you can customize things to meet your local needs. If you didn't need a bespoke solution, you'd just buy some off-the-shelf solution, integrate and get on with it.
Or I should've made PostComment as aggregate root too and added the logic of add/delete in it?
Maybe. Aggregates are best thought of as atoms, you load the entire aggregate, make your changes, save the results.
So if you find yourself with many concurrent attempts to modify the same aggregate, then you have to deal with a bunch of contention issues. Alice can't change her comment while Bob is changing his; we have to do them one at a time (to avoid losing changes).
On the other hand, if each comment is an aggregate of its own, then Bob and Alice can make their changes in parallel, without needing to rerun the "business logic" because the other person's change happened first.
Which is great, when it is free. But it isn't free -- the cost you pay is that the information is now distributed, and you have to deal with the fact that the changes have different timing. You'll sometimes see "eventual consistency" used here -- because the authoritative information is distributed, there will be times where not all of the observers have the same sets of changes.
In most domains, this is fine: race conditions don't exist. But trying to perform an all or nothing change across distributed data is a nightmare.
On the other hand, if you are willing to accept that changes happen at different times, then separating the aggregates out is fine.
Example: Twitter. Bob tweets something dumb. Alice tweets that Bob is dumb, with a link to his tweet. Bob deletes his tweet. And that's all fine, because we're comfortable with the fact that Alice's tweet has a link to something that is no longer available.
It is often the case that information that comes from the outside world can be its own aggregate, because what we are really doing at that stage is caching data, which is already stale by the time we receive it.
You may also want to review Mauro Servienti's talk All Our Aggregates Are Wrong, which discusses the heuristics for breaking down an aggregate into smaller pieces.
Am I doing this correctly? I mean, is the business logic in the right place? Or I should've made PostComment as aggregate root too and added the logic of add/delete in it?
Partially! I consider the logic is in the right place and PostComment should not be an aggregate root. But if you wants to take off more about DDD I consider that there are some another points to review before continue. I hope I can help you some way in the explanations bellow.
I have reviewed the code and refactored it to explain some points you can reconsider. Try to read it, compare and understand before read my explanation below.
// you can simplify your DomainModel removing the IAggregate plus adding generics
public abstract class Entity<T>
{
public T Id { get; set; }
}
// this is an Aggregate Root
public class Person : Entity<int>
{
public string Name { get; set; }
public string Avatar { get; set; }
public override string ToString()
{
return Name;
}
}
//this is an Aggregate Root
public class Post : Entity<int>
{
private List<Comment> _comments = new List<Comment>();
public string Title { get; set; }
public string Content { get; set; }
public Person Author { get; set; }
public IReadOnlyList<Comment> Comments => _comments;
public void Reply(Comment comment)
{
_comments.Add(comment);
}
public void Delete(Comment comment, int personId)
{
if (!AreSame(comment.Author, personId))
throw new Exception("You cannot delete a comment that is not yours. blablabla");
_comments.Add(comment);
}
private bool AreSame(Person author, int personId)
{
return author.Id == personId;
}
public override string ToString()
{
return Title;
}
}
// this is a Value Object part of Post Aggregate
public struct Comment
{
public DateTime Date;
public string Text;
public Person Author;
public Comment(DateTime date, string text, Person author)
{
Date = date;
Text = text;
Author = author;
}
public override string ToString()
{
return $"{Date} - {Author}: {Text}";
}
}
If the PostComment is part of Post Aggregate, it can't be an EntityBase, because each Aggragate should have only one root (Id). You're modeling a domain where a Post may have N Comments. You can consider the PostComment as a Value Object instead an Entity removing his Id.
You should pay attention about the names you are using. Try to sound more natural. It is called, ubiquitous language, the words everybody speak.
User is a description that just have a sense in system's context, in other words, you should have a User if you dealing with Security or Authentication contexts, in a Blog Context you have a Person acting as Author.
Increase readability using terms your users says. Reply may be more natural than AddComment.
public void Reply(Comment comment)
{
_comments.Add(comment);
}
Increase readability adding names for your conditions:
public void Delete(Comment comment, int personId)
{
if (!AreSame(comment.Author, personId))
throw new Exception("You cannot delete a comment that is not yours. blablabla");
_comments.Add(comment);
}
private bool AreSame(Person author, int personId)
{
return author.Id == personId;
}

Neo4jClient does not add properties to a relationship

We have been trying to write a C# client that seeds a Neo4j instance with some nodes and relationships. We are facing probelms when trying to create relationship properties.
Here is the code to create the relatioship with the flag property:
var s = clientConnection.CreateRelationship(root, new RelationshipPrincipleToContent("SECURITY", rootFolder) { flags = "+W" });
Here is the relationship class:
public class RelationshipPrincipleToContent : Relationship, IRelationshipAllowingSourceNode<Principles>, IRelationshipAllowingTargetNode<Content>{
public string flags { get; set; }
string RelationshipName;
public RelationshipPrincipleToContent(NodeReference targetNode) : base(targetNode){}
public RelationshipPrincipleToContent(string RelationshipName, NodeReference targetNode): base(targetNode){
this.RelationshipName = RelationshipName;
}
public override string RelationshipTypeKey{
get { return RelationshipName; }
}
}
When we look at the data in the data browser tab there are no properties on the relationships. We have also created a relationship index?
What are we missing/ doing wrong?
Firstly add a class (PayLoad.cs in this instance) that holds a set for a public string.
public class PayLoad
{
public string Comment { get; set; }
}
Update your relationship class to use this PayLoad class:
public class RelationshipPrincipleToContent : Relationship<PayLoad>, IRelationshipAllowingSourceNode<Principles>, IRelationshipAllowingTargetNode<Content>
{
string RelationshipName;
public RelationshipPrincipleToContent(string RelationshipName, NodeReference targetNode, PayLoad pl)
: base(targetNode, pl)
{
this.RelationshipName = RelationshipName;
}
public override string RelationshipTypeKey
{
get { return RelationshipName; }
}
}
}
Now just update your method call on the relationship class:
clientConnection.CreateRelationship(AllPrincipals, new RelationshipPrincipleToContent("SECURITY", rootFolder, new PayLoad() { Comment = "+R" }));
(Context: I lead the Neo4jClient project.)
Shaun's answer is correct, however dated.
The direction of both Neo4j and Neo4jClient is towards Cypher as a unified approach to everything you need to do.
This Cypher query:
START root=node(0), rootFolder=node(123)
CREATE root-[:SECURITY { flags: 'W+' }]->rootFolder
Is this in C#:
client.Cypher
.Start(new { root = client.RootNode, rootFolder })
.Create("root-[:SECURITY {security}]->rootFolder")
.WithParam("security", new { flags = "+W" })
.ExecuteWithoutResults();
Some notes:
Using Cypher for this type of stuff might look a bit more complex to start with, but it will grow better for you. For example, a simple switch from Create to CreateUnique will ensure you don't create the same relationship twice; that would be much harder with the procedural approach.
Non-Cypher wrappers in Neo4jClient are a bit old and clunky, and will not see any significant investment moving forward
The C# approach uses WithParam to ensure that everything gets encoded properly, and you can still pass in nice objects
The C# approach uses WithParam to allow query plan caching

Accessing custom objects in DomainService from client

I am using Domain Service to fetch data from database from Silverlight Client.
In DomainService1.cs, I have added the following:
[EnableClientAccess()]
public class Product
{
public int productID;
public string productName;
public List<Part> Parts = new List<Part>(); //Part is already present in Model designer
}
In DomainService1 class I added a new method to retrive a collection of the custom class object:
[EnableClientAccess()]
public class DomainService1 : LinqToEntitiesDomainService<HELPERDBNEWEntities1>
{
...
public List<Product> GetProductsList(...)
{
List<Product> resultProducts = new List<Product>();
...
return resultProducts;
}
}
From the silverlight client I am trying to access that method:
DomainService1 ds1 = new DomainService1();
var allproductList = ds1.GetProductsList(...);
ds1.Load<SLProduct>(allproductList).Completed += new EventHandler(Load_Completed); //Not correct usage
However it is not the correct way to call the new method. The reason I added a new class Product in DomainServices.cs is to have an efficient grouping. I cannot achieve the same using the model classes auto-generated by the entity framework.
How call I call the new method from the client?
I believe there is a similar question with an answer here:
Can a DomainService return a single custom type?
Also, here is some discussion about the overall problem of adding custom methods in a Domain Service:
http://forums.silverlight.net/t/159292.aspx/1
While I don't know what you mean by "it is not the correct way to call the new method", or if you're getting any errors, I thought maybe posting some working code might help.
My POCO
public class GraphPointWithMeta
{
[Key]
public Guid PK { get; set; }
public string SeriesName { get; set; }
public string EntityName { get; set; }
public double Amount { get; set; }
public GraphPointWithMeta(string seriesName, string entityName, double amount)
{
PK = Guid.NewGuid();
SeriesName = seriesName;
EntityName = entityName;
Amount = amount;
}
// Default ctor required.
public GraphPointWithMeta()
{
PK = Guid.NewGuid();
}
}
A method in the domain service (EnableClientAccess decorates the class)
public IEnumerable<GraphPointWithMeta> CallingActivityByCommercial()
{
List<GraphPointWithMeta> gps = new List<GraphPointWithMeta>();
// ...
return gps;
}
Called from the Silverlight client like
ctx1.Load(ctx1.CallingActivityByCommercialQuery(), CallingActivityCompleted, null);
client call back method
private void CallingActivityCompleted(LoadOperation<GraphPointWithMeta> lo)
{
// lo.Entities is an IEnumerable<GraphPointWithMeta>
}
I am not sure if your Product class is an actual entity or not. From the way it is defined, it does not appear to be an entity. My answer is assuming it is not an entity. You will need to apply the DataMemberAttribute for your Product properties, and you wouldn't load the product list - load is for Entity Queries (IQueryable on the service side). You would just invoke it like this (client side):
void GetProductList( Action<InvokeOperation<List<Product>>> callback)
{
DomainService ds1 = new DomainService();
ds1.GetProductsList(callback, null);//invoke operation call
}
And the domain service's (server side) method needs the InvokeAttribute and would look like this:
[EnableClientAccess]
public class MyDomainService
{
[Invoke]
public List<Product> GetProductList()
{
var list = new List<Product>();
...
return list;
}
}
And here is how your Product class might be defined (if it is not an entity):
public class Product
{
[DataMember]
public int productID;
[DataMember]
public string productName;
[DataMember]
public List<Part> Parts = new List<Part>(); // you might have some trouble here.
//not sure if any other attributes are needed for Parts,
//since you said this is an entity; also not sure if you
//can even have a list of entities or it needs to be an
//entity collection or what it needs to be. You might
//have to make two separate calls - one to get the products
//and then one to get the parts.
}
Like I said, i am not sure what Product inherits from... Hope this helps.

Manual Creation of Classes Vs. DBML

I'm currently creating objects for an application of mine when this stuff come to mind. I know that using DBML's over Manual Creation of classes(see class below) can improve the speed of my application development but I'm really confused of what would be the other disadvantages and advantages of using DBML's over Manual Creation of classes like what I'm doing below thanks for all people who would help. :)
[Serializable]
public class Building
{
public Building()
{
LastEditDate = DateTime.Now.Date;
LastEditUser = GlobalData.CurrentUser.FirstName + " " + GlobalData.CurrentUser.LastName;
}
public int BuildingID { get; set; }
public string BuildingName { get; set; }
public bool IsActive { get; set; }
public DateTime LastEditDate { get; set; }
public string LastEditUser { get; set; }
public static bool CheckIfBuildingNameExists(string buildingName, int buildingID = 0)
{
return BuildingsDA.CheckIfBuildingNameExists(buildingName, buildingID);
}
public static Building CreateTwin(Building building)
{
return CloningUtility.DeepCloner.CreateDeepClone(building);
}
public static List<Building> GetBuildingList()
{
return BuildingsDA.GetBuildingList();
}
public static List<Building> GetBuildingList(bool flag)
{
return BuildingsDA.GetBuildingList(flag).ToList();
}
public static Building SelectBuildingRecord(int buildingId)
{
return BuildingsDA.SelectBuilding(buildingId);
}
public static void InsertBuildingRecord(Building building)
{
BuildingsDA.InsertBuilding(building);
}
public static void UpdateBuildingRecord(Building building)
{
BuildingsDA.UpdateBuilding(building);
}
public static void DeleteBuildingRecord(int building)
{
BuildingsDA.DeleteBuilding(building);
}
}
and my DAL is like this:
internal static class BuildingsDA
{
internal static Building SelectBuilding(int buildingId)
{
SqlCommand commBuildingSelector = ConnectionManager.MainConnection.CreateCommand();
commBuildingSelector.CommandType = CommandType.StoredProcedure;
commBuildingSelector.CommandText = "Rooms.asp_RMS_Building_Select";
commBuildingSelector.Parameters.AddWithValue("BuildingID", buildingId);
SqlDataReader dreadBuilding = commBuildingSelector.ExecuteReader();
if (dreadBuilding.HasRows)
{
dreadBuilding.Read();
Building building = new Building();
building.BuildingID = int.Parse(dreadBuilding.GetValue(0).ToString());
building.BuildingName = dreadBuilding.GetValue(1).ToString();
building.IsActive = dreadBuilding.GetValue(2).ToString() == "Active";
building.LastEditDate = dreadBuilding.GetValue(3).ToString() != string.Empty ? DateTime.Parse(dreadBuilding.GetValue(3).ToString()) : DateTime.MinValue;
building.LastEditUser = dreadBuilding.GetValue(4).ToString();
dreadBuilding.Close();
return building;
}
dreadBuilding.Close();
return null;
}
....................
}
I would also want to know if what could be the faster between the two methods of OOP implementation thanks :)
DBML
Pros:
You can get your job done fast!
Cons:
You can't shape your entity the way you want, for example you need 5 columns from the table but it has 10 columns you will get all of them, at least its schema. If you don't care much about data volum
You client side will have dependency with DAL (Data Access Layer), if you change property name, type in DAL you need to change in both BLL (Business Logic Layer) and client (Presentation Layer)
If you manual create class you might take a little bit more time to code but you get more flexible with it. Your client code will not depend on your DAL, any changes on DAL will not cause problems on client code.
Creating your model classes manually you can put additional attributes to properties (it cannot be done with DBML), apply your own data validation (as far as I remember it is possible to be done with DBML using partial methods).
With many tables and assocatiations DBML could become hard to read.
Disadventage of creating model classes manually is that you have to do all DBML stuff (attributes and a lot of code).
If you want to create model classes manually you can take a look at Entity Framework Code First or Fluent NHibernate. Both allows creating model easily.

What is a better, cleaner way of using List<T>

I'm looking to implement a few nicer ways to use List in a couple of apps I'm working on. My current implementation looks like this.
MyPage.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
BLL.PostCollection oPost = new BLL.PostCollection();
oPost.OpenRecent();
rptPosts.DataSource = oArt;
rptPosts.DataBind();
}
BLL Class(s)
public class Post
{
public int PostId { get; set; }
public string PostTitle { get; set; }
public string PostContent { get; set; }
public string PostCreatedDate { get; set; }
public void OpenRecentInitFromRow(DataRow row)
{
this.PostId = (int) row["id"];
this.PostTitle = (string) row["title"];
this.PostContent = (string) row["content"];
this.PostCreatedDate = (DateTime) row["createddate"];
}
}
public class PostCollection : List<Post>
{
public void OpenRecent()
{
DataSet ds = DbProvider.Instance().Post_ListRecent();
foreach (DataRow row in ds.Tables[0].Rows)
{
Post oPost = new Post();
oPost.OpenRecentInitFromRow(row);
Add(oPost);
}
}
}
Now while this is working all well and good, I'm just wondering if there is any way to improve it, and just make it cleaner that having to use the two different classes do to something I think can happen in just one class or using an interface.
For one thing, I wouldn't derive from List<T> - you aren't really specializing the behaviour.
I'd also suggest that you could make Post immutable (at least externally), and write a static method (or constructor) to create one based on a DataRow:
public static Post FromDataRow(DataRow row)
Likewise you can have a list method:
public static List<Post> RecentPosts()
which returns them. Admittedly that might be better as an instance method in some sort of DAL class, which will allow mocking etc. Alternatively, in Post:
public static List<Post> ListFromDataSet(DataSet ds)
Now, as for the use of List<T> itself - are you using .NET 3.5? If so, you could make this considerably neater using LINQ:
public static List<Post> ListFromDataSet(DataSet ds)
{
return ds.Tables[0].AsEnumerable()
.Select(row => Post.FromDataRow(row))
.ToList();
}
Are you deriving from List<T> because you want to offer other consumers of PostCollection the ability to Add and Remove items? I'm guessing not, and that you actually just want a way to expose a collection you can bind to. If so, you could consider an iterator, perhaps:
class BLL {
...
public IEnumerable<Post> RecentPosts {
get {
DataSet ds = DbProvider.Instance().Post_ListRecent();
foreach (DataRow row in ds.Tables[0].Rows)
{
Post oPost = new Post();
oPost.OpenRecentInitFromRow(row);
yield return oPost;
}
}
}
...
}
Notwithstanding the fact that this might be considered poor form (in that we have a property getter that might be making a network call), this iterator approach will do away with the overhead of calling OpenRecentInitFromRow for Posts that are never enumerated.
You also become agnostic as to how potential consumers of your Posts might want to consume them. Code that absolutely, positively has to have every Post can do ToList(), but other code might want to use a LINQ query that short-circuits the enumeration after the right Post is found.
Edit: John Skeet's answer is probably a better option. But if you want to make just a few simple changes, read on:
Place the database access code, OpenRecentInitFromRow into the PostCollection and treat that as a Post manager class. That way the Post class is a plain old Data Transfer Object.
public class Post
{
public int PostId { get; set; }
public string PostTitle { get; set; }
public string PostContent { get; set; }
public string PostCreatedDate { get; set; }
}
public class PostCollection : List<Post>
{
public void OpenRecent()
{
DataSet ds = DbProvider.Instance().Post_ListRecent();
foreach (DataRow row in ds.Tables[0].Rows)
{
Add(LoadPostFromRow(row));
}
}
private Post LoadPostFromRow(DataRow row)
{
Post post = new Post();
post.PostId = (int) row["id"];
post.PostTitle = (string) row["title"];
post.PostContent = (string) row["content"];
post.PostCreatedDate = (DateTime) row["createddate"];
return post;
}
}
I'm looking to implement a few nicer ways to use List
That seems like an odd request. The "List" type is a means, rarely an end. With that in mind, one nicer way to accomplish your real end is to use IEnumerable rather than List, because that List forces you to keep your entire collection in memory while IEnumerable only requires one object at a time. The trick is just that you have to wire everything in your processing stream, from the data layer all the way up through presentation, to use it.
I have a good example in the link below about how to do this in a very clean way:
Fastest method for SQL Server inserts, updates, selects
Depending on your existing data layer code you may be able to skim much of the first half of the (long) post - the main point is that you use an iterator block to turn an SqlDataReader into an IEnumerable<IDataRecord>. Once you have that, it's pretty straightforward the rest of the way through.
You could do this:
protected void Page_Load(object sender, EventArgs e)
{
BLL.PostCollection oPost = new BLL.PostCollection();
rptPosts.DataSource = Post.OpenRecent();
rptPosts.DataBind();
}
public class Post
{
public int PostId { get; set; }
public string PostTitle { get; set; }
public string PostContent { get; set; }
public string PostCreatedDate { get; set; }
public void OpenRecentInitFromRow(DataRow row)
{
this.PostId = (int) row["id"];
this.PostTitle = (string) row["title"];
this.PostContent = (string) row["content"];
this.PostCreatedDate = (DateTime) row["createddate"];
}
public static List<Post> OpenRecent()
{
DataSet ds = DbProvider.Instance().Post_ListRecent();
foreach (DataRow row in ds.Tables[0].Rows)
{
Post oPost = new Post();
oPost.OpenRecentInitFromRow(row);
Add(oPost); //Not sure what this is doing
}
//need to return a List<Post>
}
}

Categories

Resources