I have database first entities with different primary id names... EmployeeID, CustomerID etc. I am attempting to build a generic repository and UoW and want to know if there is anyway, without changing the database, to tell the UoW that every primary id in database, i.e. employeeid etc, will just be called id?
Thanks
I guess my question wasn't clear, so I will try an example of what I need to do. Thanks for your patience.
I have 3 tables, customer, orders and orderdetails,
The customer table has a primary key field CustomerID.
The orders table has a primary key field OrderID
The orderdetails table has a primary key field orderdetailsid.
I have 3 entities, generated from edmx, that represent each table.
I have a generic repository and unit of work to monitor save changes. I would like to have a generic way of saying that the customerid primary key will be known as id, the orderid primary key will also be known as id, and lastly the orderdetailsid will also be known as id.
I believe using a generic will allow me to create an interface that will return the primary key.
public interface IEntity {
int Id { get; }
}
I believe I can go through all my entities in the designer and change the primary key name without affecting the database, but that would be real time consuming when there may be a way of doing this within the application.
Thanks
In my experience the only way to achieve this type of mapping is to set the column name either through fluent configuration using model builder or by setting the column name using the Data Annotations API on your models
ie Data Annotations
[Column("EmployeeId")]
public int ID { get; set; }
or Fluent
In your Context class
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>().Property(e=>e.Id).HasColumnName("EmployeeId");
base.OnModelCreating(modelBuilder);
}
but this would require you to not use edmx or write a inherited DbContext to customize your you may also want to look into Entity framework power tools to remove the dependency on designers while maintaining your abiliy to quickly generate your entity classes which will make your classes more customizable as far as mapping your entity
Another option in the latter case you could write a DbConvention that would customize your mappings as well this article provides some examples of writing custom Database conventions for Entity framework http://msdn.microsoft.com/en-us/data/jj819164.aspx
Related
Source:
DictionaryTable:
DictID int
RUWordID int -> FK to RUWordsTable.RUWordID
ENWordID int -> FK to ENWordsTable.ENWordID
RUWordTable:
RUWordID int
Word string
ENWordTable:
ENWordID int
Word string
I want be able read/write data to table that uses following structure:
RUWord ENWord
Привет Hello
...
What the best option in terms of speed and easy data access from MVC views to do what i want. As per my understanding there is options to create SQL view and use it (but not sure about possible INSERTS of data). Or just create the same but using Entity Framework in Visual Studio designer.
Basically one word could be transalted differently (have several entries in other table). My goal to find a way how to add words to dictionary with automatic inserts (when source or translation not found add it to reference table, if found - just use existing entry)
It depends much on the amount of data you need to read in one go. If you want to look up translations of one or a few words an Entity Framework model will do a perfect job. If you need to fetch massive amounts of data a view or stored procedure will be better. But I don't expect the latter to happen. In an MVC view you'll probably use paging.
As for inserting data EF will be a viable choice. You already have a junction table defined (DictionaryTable). You could set up EF in a way that the junction table is transparent:
class RuWord
{
public int Id { get; set; }
public string Word { get; set; }
public ICollection<EnWord> EnWords { get; set; }
}
class EnWord
{
public int Id { get; set; }
public string Word { get; set; }
public ICollection<RuWord> RuWords { get; set; }
}
(supposing you'd work code-first)
In data entry you can add a new Russian word to the RussianWords DbSet of the context and add new or existing English words to the word's EnWords collection and call SaveChanges(). EF will insert the words and the appropriate records in the junction table (having both foreign keys as its composite primary key).
But... In real life I hardly ever see a pure junction table. I bring this in because in your case I can hardly imagine that just registering the associations between Russian and English words will be sufficient. Are you not (at least) going to need some degree of preference? Like there are more translations of the word "date", but the preferred one would be the calendar thing (unless you're working for a dating site, but even then...). Anyway, if there is something you want to record about the association you need to map the junction table explicitly and create the association records will all their details in code.
I hope this gives some directions.
Edit (after your comment)
If you use an explicit junction entity (i.e. a class that corresponds with the junction table). This entity can have the two properties EnWord and RuWord as references to the two tables mentioned above. Data entry would imply creating a new DictionaryTable instance and setting its properties (which can be new or existing words).
I'm looking for a shortcut. I have some NH entities with a many-to-many relationship. Something like this:
public class Customer : EntityBase<Customer>
{
public virtual IList<Category> Categories { get; set; }
}
public class Category : EntityBase<Category>
{
public virtual IList<Customer> Customers { get; set; }
}
Bear in mind this is a very simple depiction, so resist the temptation to suggest I not use a many-to-many arrangement or that I should use a value type or anything like that.
On the DB side, this relationship is accomplished via a separate table with two columns - Customer_Id and Category_Id.
I'd really like to be able to add an existing Category to a Customer without having to retrieve the full entity from the database. Maybe something like this:
customerEntity.Categories.Add(new Category { Id = 2 });
The reason for this is that the application is an ASP.NET MVC app and I'm using ViewModels for my views. These Customer ViewModels end up with a List<int> for the category selections, and when I go to map that ViewModel to the corresponding Customer entity, I'd love to just be able to suck those category IDs into the Categories list without having to hit the database to retrieve them first.
Part of the reason I want to be able to do this is that I'd like to minimize database calls, but I also would like to have my mapper class be able to create the Customer entity without having to make calls to my service layer to go asking for other objects...that seems like bad design. I'd also like to avoid having to add another layer to call the mapper then do the other mapping stuff that pulls entities from the repository (which is itself accessed through a domain service layer).
I checked out idbag, but for one I'm using Fluent NHibernate and it doesn't support that construct, and for two from what I can glean from the docs that will give me a List<int> on the entity, and I'd still like to be able to access the full entity in those collections.
Am I asking too much out of NHibernate?
Use ISession.Load:
customerEntity.Categories.Add(session.Load<Category>(2));
Load will return a proxy and does not hit the database. You can access the ID property of the proxy without hitting the database, but NHibernate will load the proxy if you access any other properties.
Does anyone know how the object can be made so that it does have something in its identity field - so that i can then use this to get the hash code.
One option is to use Guid as id. This way you don't need database round trip to get identity value.
<id name="_id" column="PersonId" >
<generator class="assigned" />
</id>
Or
Id(x => x.Id)
.Column("PersonId")
.GeneratedBy.Assigned();
'PersonId' column type should be uniqueidentifier if you use SQL Server. Then when you create object you can use Guid.NewGuid() to generate new id.
public class Person {
private Guid _id;
public Person() {
_id = Guid.NewGuid();
}
public Guid Id {
get { return _id; }
}
}
The advantage of this approach is that your code is more decoupled from database. This will be very helpful during tests and if you need to support 'disconnected' scenarios. Potential disadvantage is the performance during joins (google "guid vs int primary key"). See this for additional information on id generators in NHibernate.
As a side note, you may want to rethink your design and implement your Equals and GetHashCode using business key. You will not need Guid identity in this case. From Don't Let Hibernate Steal Your Identity:
"We recommend implementing equals() and hashCode() using Business key
equality. Business key equality means that the equals() method
compares only the properties that form the business key, a key that
would identify our instance in the real world (a natural candidate
key)" (Hibernate Reference Documentation v. 3.1.1).
WEll it depends on what kind of concurrency you want to achieve how long your unit of work is.. although GUId ids and HILO ids sound all fancy and cool most of the times they are not necessary.
regarding your problem you need to do a save on the database for the id to be generated provided the id is an auto incremented id generated by the db, this might hold a temporary lock on that table till your transaction is committed but that is one of the disadvantages of having an auto incremented id
and the other thing why would you save and compare the object against something else its bound to have a different id..
say Student is your class with two properties Id, Name, School
now if you want to see if its the same student then you probably want your hash generated on Name and School rather than Id
Disclaimer: I'm outlining simplified picture to emphasize main point of my question.
The application I'm working on maintains a set of resources. We have a corresponding table and mapped entity in NHibernate. Each resource identified by integer id. Also we have user table and corresponding entity to maintain user profiles.
We need to log user accesses to the application and retrieve access history. For repository class we have to introduce 2 methods:
IEnumerable GetUserLog(User user) to retrieve user access history order by date in descending order and
void WriteLogEntry(User user, Resource resource) to write new entry
I have tried to simply define LogEntry entity as following:
public class LogEntry
{
public virtual User User {get; set;}
public virtual Resource Resource {get; set;}
public virtual DateTime Date {get; set;}
}
and map it using Fluent NHibernate as usually. To retrieve/update log entries we can simply use
Session.Query<LogEntry>().Where(entry => entry.User = currentUser).OrderByDesc(entry => entry.Date)
Session.Save(new LogEntry() {
User = currentUser,
Resource = resource,
Date = DateTime.Now
})
This is the most convenient way to deal with this issue for us.
Problem
The problem is that NHibernate requires id mapping. We have to use composite id here and the only option is to map User, Resource and Date columns because only this combination provides uniqueness. Also in case of composite id we have to override Equals and GetHashCode and all this seems to be overkill for such a simple task. Another problem that lazy loading cannot be used for id fields and it's too much as well. We do not want to load all related Resource entities in advance.
Another possible solution is to define plain class, not entity and then use SetResultTransformer(Transformers.AliasToBean()) to retrieve results. In that case we have to construct queries manually, retrieve related entities manually and this way it's not better in general then dealing with raw connection.
I would like to ask expert opinion because I'm confident people around had similar experience and can help. Thanks in advance.
P.S. This is ASP.NET MVC application using NHibernate 3 (+ Fluent). Log information will be used to display last 5-10 resources user accessed.
have you considered introducing an Id field for LogEntry table as well?
many DBAs will recommend it and it seems like the easiest solution.
I am trying to create a mapping to a database table that has no primary keys/references.
public class TestMap : ClassMap<<Test>Test> {
public TestMap() {
WithTable("TestTable");
Map(x => x.TestColumn);
}
}
This fails and expects id or composite-id. Is this possible in fluent nhibernate?
In Oracle at least, I have used "ROWID" for this. For mssql you might use the "ROW_NUMBER()" builtin function for readonly access to the table, but I haven't tried that...
No. You'll have to add a surrogate primary key, such as an identity column in SQL Server, to map this table. As far as I know, this isn't supported by NHibernate itself.
Why don't you have a primary key on this table?
This functionality isn't supported by nhibernate as far as I know. As a general rule of thumb, however, you should really always have some kind of ID and if you find yourself in a situation where you think you don't need one you should assess your data model. An ID, whether it be a table-specific primary key, or a surrogate key from another table, should exist. This not only ensures that nhibernate can process the table, but helps performance via indexing.
Before you start assuming nhibernate isn't going to fulfill your needs, consider why you don't have a key on the table and what kind of sense it makes not to have one.
If we can bring a column from table having no primary key/identity coulmn, then we can use fluent as below:
Id(x => x.TempID).Column("TempID");
If the table contains data that belongs to another entity, you could map it as a collection of components. Components are not identified by themselves, but they belong to another entity, which is identified.
You can map an entity to a table without keys defined in the database. I do so in legacy SQL Server databases. However, the table must have a candidate key (some set of columns that actually stores a unique combination of values). The concept of entity involves the notion of some kind of identity.
Instead of this, what you're trying in your code is to map an entity without identity, wich isn't possible.