How can I Store ChatRoom with only the SiteId instance of full object ?
thanks
public class ChatRoom
{
public ObjectId Id { get; set; }
public DateTime StartDate { get; set; }
public **Site** **Site** { get; set; }
}
That's pretty straightforward if you're willing to change the model:
public class ChatRoom
{
public ObjectId Id { get; set; }
public DateTime StartDate { get; set; }
public ObjectId SiteId { get; set; }
}
However, that means that you need to ensure referential integrity yourself. For instance, if the Site you want to refer to hasn't been stored yet, you will first have to store the Site in the database, then store the ChatRoom with the SiteId set to the Id of the referenced Site - otherwise, there's no Id to refer to.
More importantly, that means you're no longer working with an object graph, or domain model in your code. This has impact on your entire code architecture.
For example, you can't build expressions like MyUser.ChatRoom.Site.Owner.Address.Street. That has disadvantages, because you effectively can't implement a domain model at all, but it also comes with advantages because it's unclear when the freight trains actually would talk to the database.
However, these 'freight trains' are often dangerous, because it's unclear when the respective elements are loaded from the database.
Related
I'm new to OData and I have a working solution for complex requests of my domain data, which is great. The bit I'm looking for help with is using this data and sending the entire list to another API to append additional data to the OData response for a particular object type.
I don't mind losing the ability to further query the appended collection, this can be done later in my front end. I'm looking for some help in identifying the right architecture for my solution.
I've seen a few possible answers that would be to create a custom serializer or use AutoMapper to populate the DTO but this would send the requests to the other API one at a time. I'm looking to send the entire list as the performance is improved rather than one at a time as there can be 20,000+ items in the response.
Here's my current schema.
Domain
public class InventoryItem
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual string DeviceName { get; set; }
}
DTO
public class InventoryItem
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual string DeviceName { get; set; }
public IList<ReadingDto> Readings { get; set; } = new List<ReadingDto>();
}
public class ReadingDto
{
public double? Value { get; set; }
}
As the ReadingDto is obtained from another API, this shouldn't be present in my domain model. It would never be populated.
The ideal solution would be to utilise a service within my project which would send the list over to the other API whilst maintaining the flexibility of using OData. Whether this is in a custom serializer, middleware or filters, I'm just not sure what would be best.
I am new to full stack software development, and I have an assignment to create a simple full stack web app in .NET Core, Entity Framework Core (when it comes to the back-end part), which would store some employee data. Now, let's say I have an Employee entity. We also need to implement the Employee's position in some way (an employee can have the position of a back-end developer, front-end developer, project manager etc.). That's why I have also created this EmployeePosition class, so that there is an EmployeePosition property in Employee. I also have other similar status enitities like the EmployeePosition in the app.
EmployeePosition would then be seeded to a separate table in the database, and thus it can be applicable to any company that "would use" this app (just use different seed data). I will use a legacy database for seeding.
Now it seems that this would work, but it also seems a bit too crude for me, because whenever I would need to do an operation with the status in the repository, I would have the use the magic Id number of the status, or hardcode the status Name property somewhere in a method (if I don't have a smarter workaround for the given operation), for instance "Switch(Position.Name) case "front-end": do stuff" etc.
Could I maybe get a suggestion or direction on how to implement this better, am I on a good track here?
Would it be better to actually use enums as data types inside of EmployeePosition, any suggestions on how to implement that? Considering that I have to use the legacy database for seeding, I would have to somehow create my enums out of the legacy file.
public class Employee
{
[Key]
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Image { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Phone { get; set; }
[Required]
public EmployeePosition Position { get; set; }
public class EmployeePosition
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
What you can do is create an Enum for employee positions.
public enum EmployeePosition
{
Backend = 0,
Frontend = 1,
DBA = 2,
}
And your employee entity
public class Employee
{
[Key]
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Image { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Phone { get; set; }
[Required]
public EmployeePosition Position { get; set; }
}
Then you can use
If (Employee.Position == EmployeePosition.Backend)
{
// your logic.
}
You have conflicting requirements unfortunately. You say that your program is "status-agnostic":
EmployeePosition would then be seeded to a separate table in the database, and thus it can be applicable to any company that "would use" this app (just use different seed data).
And yet, it's really not:
Because whenever I would need to do an operation with the status in the repository, I would have the use the magic Id number of the status, or hardcode the status Name property somewhere in a method (if I don't have a smarter workaround for the given operation), for instance "Switch(Position.Name) case "front-end": do stuff" etc.
So one of those requirements has to "win". Either your code knows what the different statuses are (and so different seed data wouldn't work) or it doesn't.
If the first requirement is more important:
Keep your code as it is, you have a perfectly reasonable model for N number of statuses where they aren't known ahead of time, nor is any logic specific to a given entry
If the second requirement is more important:
Switch to an enum. You don't want magic numbers or strings floating around in your code. As you mention, you'll need to map each existing data row into one of the predefined enum members.
I am using mongodb C# driver and trying to add "Goal" Entity in the "List", contained in Client class, but mongodb always returns an empty objectId og Goal.
Client.cs
public class Client
{
public string UserName { get; set; }
[BsonId]
public ObjectId ClientId { get; set; }
[BsonIgnore]
public string ClientIdString
{
get
{
return this.ClientId.ToString();
}
}
[BsonRequired]
public string ClientName { get; set; }
public string EmailAddress { get; set; }
public string CompanyName { get; set; }
public List<Goal> Goals { get; set; }
}
Goal.cs
public class Goal
{
public ObjectId GoalId { get; set; }
[BsonRequired]
public string Title { get; set; }
public string Description { get; set; }
[BsonDefaultValue(State.NotStarted)]
public State GoalState { get; set; }
[BsonIgnore]
public string StateString
{
get
{
return this.GoalState.ToString();
}
}
}
and i am trying to add Goal to client with following code:
IMongoQuery query = Query<Client>.EQ(eq => eq.ClientId, id);
IMongoUpdate update = Update<Client>.Push<Goal>(push => push.Goals, goal);
WriteConcernResult result = this.ClientCollection.Update(query, update);
But every time mongodb returns an empty objectId of newly added Goal in the List in client.
Kindly guide me what i am doing wrong?
Thanks in advance. :)
Kindly guide me what i am doing wrong?
Nothing really, but you're expecting the wrong behavior.
Embedded documents don't have an _id. Of course, you can force mongodb to create a field that happens to have that name, but unlike the root _id, such a field has no special semantics and there's no default index. The lack of these special semantics is also the reason why the driver doesn't bother generating a value for the field for you.
Generally speaking, having a unique index in an embedded document is often a sign of a malformed data structure. Make sure such an id is strictly required. If the id must be globally unique, it appears the embedded document might also make sense or be relevant if it had another parent, which indicates that it should be a first-level citizen, i.e. have a collection of its own.
Remember that this also a question of ownership - what happens with concurrent writes? Of course, you can go to great lengths and only use atomic modifiers to allow different writes to one document, but that is unnecessarily complicated IMHO.
In my Domain layer, I have the following two Entities for mongodb collections
public class League
{
public ObjectId Id { get; set; }
public string LeagueName { get; set; }
public List<ObjectId> Teams { get; set; }
}
public class Team
{
public ObjectId Id { get; set; }
public string UserId { get; set; }
public string Teamname { get; set; }
public int Rating { get; set; }
}
Service layer
private static IEnumerable<ObjectId> GetTeamsNotInSeason(Season season, IEnumerable<Team> teams )
{
var teamsInSeason = season.Leagues.Where(x => x.Teams != null).SelectMany(x => x.Teams).ToList();
return teams.OrderByDescending(x => x.Rating).Select(x => x.Id).Except(teamsInSeason);
}
So each League has a list of Teams, referencing use ObjectId. But that means in my service layer it needs to know about ObjectId, hence I have to have a mongoDb reference in there. So my question is, do you have to store relationship references as a type of ObjectId, What is the normal standard for relationships in mongodb? Within c#
Yoe need to analyze first the reads vrs the writes that you are going to have in the database.
Some basic rules:
If you'll perform more reads than writes then embed as much as you can, that will improve read performance and allow to read data in a single call to the database. The choice embed or not is usually made on how data will grow, change over time and how you gonna query it.
Consider de-normalization of data for fast querying, sometimes duplicated name on other collection is not that bad as long you avoid to do multiples queries to the database.
other notes:
Denormalization always add some overhead to writes, but increase read speed. For your case I assumed will be more reads than writes and heavily used denormalization.
When reading data consider excluding fields from object when you no need them, proyections doesn't work very well on c# using linq but there are some workarounds for this particular issue so just be aware of it.
EDIT:
if you plan to have more reads than writes probably you can have a single collection with all the imofrmation.
public class League
{
public ObjectId Id { get; set; }
public string LeagueName { get; set; }
public List<Team> Teams { get; set; }
}
EDIT:
The best datatype to creating references between objects is ObjectId, however I'd be great for you to check the escenarios for data modeling in the case you haven't looked at it.
For example, I have a EF6 model like this:
class User
{
public int Id { get; set; }
public string Email { get; set; }
public string Name { get; set; }
public virtual ICollection<ProfileProperty> Properties { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
class Book
{
public int Id { get; set }
public int Name { get; set }
public DateTime CreationDate { get; set }
public long Size { get; set }
public string ContentPath { get; set }
}
And now I want to create a WebAPI that allows to:
Create a new user
Update user's name
Modify the list of user's books
However, here are a few tricks to it which don't let me use tutorials right off:
Some fields are either irrelevant or confidential and must not be exposed via WebAPI, for example: User.Id, User.Properties, and nested User.Books[x].ContentPath.
Only a small subset of fields is editable (in the example, User.Name).
Only a small subset of operations (CRUD) is available, therefore it's not a REST service.
The first thing that comes to mind is create extra classes for each exposed model. However, maintaining them and writing code that converts data from database models to those WebAPI-friendly classes and back is too bothersome. Is there a more simple and automated way?
The ideal approach would be one which requires writing as little redundant code as possible. Maybe there is a set of attributes to mark fields with?
You're right in thinking you should create more classes. For each exposed action (change name, create user, etc...) you should create a ViewModel that exposes only the fields you need.
public class ChangeUserNameViewModel
{
public int UserId { get; set; }
public string NewName { get; set; }
}
It's easy to convert your view model to your domain model and back again using something like AutoMapper.