I have a database that uses natural keys (i.e. business oriented keys). Unfortunately, because of this, the primary keys for these objects may change over time.
I am currently researching the use of NHibernate for an O/RM for this database. However, in my testing I have noticed that there is no apparent way to change the primary key of an object and save it to the database.
For example, say I have a 'Business' object with a 'BusinessCode' as it's primary key:
public class Business
{
public string BusinessCode { get; set; }
public string Name { get; set; }
...
}
If I do a Get, change the primary key, and try and save it back to the database using NHibernate, I either receive an exception or unexpected results (depending on if I use Save(), Update(), or SaveOrUpdateCopy())
Business b = session.Get<Business>("BusinessCode1");
b.BusinessCode = "BusinessCode22";
session.Update( b );
So is something like this possible?
I understand that many NHibernate folks recommend using primary keys that do not change (i.e. identities). But I have a couple DB's that use natural keys. Thanks.
I'm actually kicking myself that I even asked this question because I can easily mitigate this by doing a delete-insert type of operation. This was more of a proof-of-concept with an existing database. Thanks for your input!
Have you tried using a composite-id?
Or Assigned Identifiers?
Is adding an Auto-incremented ID field totally out of the question?
Related
I'm considering using entity framework database-first approach. The database in question uses various non-standard techniques, eg 'informal' foreign keys. I'd like to confirm that it's still possible to create a usable EF model from this database, even if all the relationships are not recognised?
Yes, you can do this. Generate the model from the database as normal, then modify the generated entities in order to introduce the relationships. You'll need to set a Null database initializer to tell EF it should not try and update the database to match its model:
Database.SetInitializer(new NullDatabaseInitializer<MyContext>());
There's no requirement for foreign keys to exist in the database to match your model - as long as the navigation properties have been added on the entities, EF will generate the correct SQL queries accordingly.
I would recommend the use of the [ForeignKey] attribute to clarify the names of your foreign key fields for when they don't conform to EF's expected patterns (or you could modify the Conventions accordingly). For example...
public class Child {
// ...
public int Parent_ID { get; set; } // <-- non-standard name
// Add these to introduce the navigation property without a formal relationship
[ForeignKey("Parent_ID")]
public virtual Parent Parent { get; set; }
}
I have used this approach on a MySQL database with no foreign keys at all.
I would like to explain my question with an example. Let's say there are many courses that students can register. Each course can have many discussion walls. Each discussion wall contains questions. Each question may have replies. And badges can be assigned to replies (or comments).
In my case, I need to know that which reply belongs to which course (when listing replies), and the same for the badges. I am able to do this with Entity Framework but the queries are becoming very complex and causing performance problems.
In this scenario, is it better to have a CourseId column in Replies (or BadgeAssignments) table? Or not? This would make my life a lot easier in some aspects, but not sure in long term. What do you think? Is it sometimes better to have some redundancy? I do no think I will need to update CourseId field later.
My pet peeve is sacrificing data integrity for performance. Obtaining a less-than-reliable answer faster is not a good solution. However, changes that improve performance that do not sacrifice data integrity are fine.
Redundancy may well sacrifice data integrity. It is certainly a critical point where anomalous data can start. The problem is that both "sets" of data must be rigidly synchronized which, depending on the design, may be easy or difficult to do. Either way, it takes system resources to maintain the synchronization so you are adding another hit on performance.
Fortunately, that performance hit will be added to the DML operations as that is where the synchronization will be performed. In general, shifting performance time from queries to DML (which are usually less sensitive to response time) can be a good solution.
The devil is in the details, however, and you provide no details. Can the performance be improved sufficiently without redundancy? What is the level of difficulty in maintaining synch between the redundant data? Another way of asking that last question would be: how likely is it for anomalous (unsynched) data to creep into the system? How much of a problem will unsynched data be and how difficult will it be to fix it?
There is not nearly enough information provided to answer these questions. But keep them in mind as you investigate solutions.
Each component of your system should be utilized as it was designed to make it the "best". Things work better when they work according to their design. This, strictly, is my answer to your question.
The Relational Database
The purpose of a relational database is first to govern the integrity of your information and second to provide a storage and retrieval system. The RDMS governs your truth which then determines the way it should be stored and retrieved.
Since it is difficult, but not impossible, for us to imagine the uniqueness of digital discussion walls and of questions and replies we will typical use surrogate keys (i.e. auto generated numbers) for those entities' primary keys. This means the decision to add the Course ID to Questions, Replies, or BadgeAssignments will violate the principals relational design. You may say "no biggie" in this instance, but it is a violation nonetheless and will have consequences as long as it persists (pun intended).
If we used natural keys for Courses, Walls, Questions, Replies, and BadgeAssignments then our Primary Keys for each of those tables would be composites from those tables. We would then, for example, have the Primary Key of Courses within the Composite Primary Key of Replies without violating any principal of redundancy or normalization and your life would be "easier".
That said, what is so hard about this query?
SELECT
D.CourseId, D.CourseName
,A.ReplyId, A.ReplyName
FROM
Replies A
JOIN Questions B On A.QuestionId = B.QuestionId
JOIN Walls C ON B.WallId = C.WallId
JOIN Courses D ON C.CourseId = D.CourseId
Entity Framework
Entity Framework (EF) can be configured to match your design whether we put CourseId in Replies or whether we rely on the joins. But, we can usually do better than EF when it comes to SQL performance.
One option would be a to craft a SQL query (starting with the one above) that has the highest amount of optimization according to your need, and turn it into a View. Then, map a C# class to the View (instead of the tables) and the interactions are simplified. We would be letting EF exceed in providing low hassle data access and SQL succeed at retrieving data.
Here is the difference in C# Linq...
var replies = context.Replies
.Where(x => x.Questions.Walls.CourseId == 1)
.Select(x => new ReplyView
{
CourseId = x.Questions.Walls.Courses.CourseId,
CourseName = x.Questions.Walls.Courses.CourseName,
ReplyId = x.ReplyId,
ReplyName = x.ReplyName
}).ToList();
versus
var replies = context.RepliesView.Where(x => x.CourseId == 1).ToList();
Since you have tagged your question with entity-framework, I'll assume you are using SQL Server, in which case you may consider using indexed views to "cache" the JOINs without worrying this cache will ever go out of sync - the DBMS will maintain it for you at all times.
For example, you can cache the JOIN between courses, students, discussion walls, questions, replies and badges. So when you want to know which badge belongs to which course, you just retrieve a single row from the indexed view, instead of performing the physical JOIN.
Alternatively, consider redesigning your keys and using identifying relationships to migrate key fields down the foreign key hierarchy, so when querying a child table you can get the key of a non-direct parent without JOINing the tables "in between".
And last but not least, I warmly recommend reading Use the Index, Luke! for fundamental knowledge every developer should have about database performance...
I'll post an example here :
public class SchoolEntities : DbContext
{
public DbSet<Department> Departments { get; set; }
}
public class Department
{
// Primary key
public int DepartmentID { get; set; }
public string Name { get; set; }
// Navigation property
public virtual ICollection<Course> Courses { get; set; }
}
public class Course
{
// Primary key
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
// Foreign key
public int DepartmentID { get; set; }
// Navigation properties
public virtual Department Department { get; set; }
}
public partial class OnlineCourse : Course
{
public string URL { get; set; }
}
public partial class OnsiteCourse : Course
{
public string Location { get; set; }
public string Days { get; set; }
public System.DateTime Time { get; set; }
}
and that's a small example ... do have any of this information?
So i like MVC and EF6 but I keep coming across fundamental problems with the way it / I work.
I have an app ( a very simple one) in there one of my tables references a field in another database, how would EF handle this , it seems to get very complicated whereas in the past it would have been a simple ADO.NET call to a stored procedure or something ( I am aware I can use SP's with EF, but really, what's the point , may as well just use ADO.NET again), example model below:
[Table("Target")]
public partial class Target
{
public int ID { get; set; }
public int SomeForeignKeyInMyDbID { get; set; }
public Guid? FOREGINKEYINANOTHERDB { get; set; }
}
when I scaffold views based of this it automatically creates the drop down menus etc really well but it (obviously) cannot pickup the reference to the foreign key in another field, as I want to store the ID of the foreign key in the database but get the value of it for drop downs etc, I store the ID instead of the value for reporting reasons.
I thought that I would just be able to get a context to my other db, grab the values I need and bind them to the drop down list but the model structure is so tightly defined that I face hurdle after hurdle on this.
I read somewhere that my best option may be to use SP's for CRUD operations and then perform a LINQ to EF query fro the index view and do a join on foreginkeyfromanotherdb field.
Any help much appreciated.
Thanks
One of the functions of our application is that it stores content information for users. The information is one of several different
content types and the available types are stored in a relational table in SQL Server. Here's the class that is used:
public partial class ContentType
{
public int ContentTypeId { get; set; }
public string Name { get; set; }
public System.DateTime ModifiedDate { get; set; }
public virtual byte[] Version { get; set; }
}
The SQL Server Table that backs up this class has the same fields:
CREATE TABLE ContentType (
[ContentTypeId] INT IDENTITY (0, 1) NOT NULL,
[Name] NVARCHAR (50) Not NULL,
[Version] rowversion,
[ModifiedDate] [datetime] NOT NULL,
CONSTRAINT [PK_ContentType] PRIMARY KEY CLUSTERED ([ContentTypeId] ASC)
)";
We would like to "internationalize" our application. This would mean that amongst other things there
would be different values for the "Name" field depending on language.
Can anyone give us any suggestions on how this could be done?
It depends what you mean by "internationalization". If you simply need support for a second language in the near to medium term, you can solve that by adding a new column in the table. Something like AlternateName.
Or, if name simply needs an associated language, you can solve that by including a LanguageId column (referencing an associated Languages table).
I'm guessing that you mean something more intense, namely the ability to look at the "name" of a "content" in one of several languages. I am also assuming that ModifiedDate is a database field not related to user content. If not, then you also need to deal with the internationalization of date formats.
Right now, your table structure has a 1-1 relationship between ContentTypeId and name. That relationship has to be modified, because you need a 1-many relationship. Start with a table of allowed languages. If you want to use abbreviations instead, go with the international standards (here for instance). Your own table, though, would allow you to include other information such as preferred date format and preferred currency symbol.
You need another table, something like ContentLanguages, something like:
create table ContentLanguages (
ContentLanguageId int primary key,
LanguageId int, /* or a code for human readability */
Name nvarchar(255),
ModifiedDate datetime
);
You then need to maintain this for multiple languages.
If you have a standard language, you will probably want to ensure that all names appear, say in English. You could do this by having a business rule that would require content to have an English version before any other version could be added (using a trigger or a business rule in a stored procedure).
The way I understand this is that you want to make more user friendlier for people who don’t know English.
I’d consider keeping database as is but only creating international interface.
For example you can create API people would use instead of direct access to database and make this API international by naming methods, classes and other with appropriate international names.
You can even go with international namespaces such sa Main.Espana.MiCasa and Main.English.MyHouse
In the background you’ll have one set of methods that would do the actual work and then just create wrappers for different languages.
Another way might be to create different schemas in database and give people access only through those schemas. Use views for reading data and stored procedures for inserting and updating.
Anybody knows how to map grails domain class to MSSQL entity witch has not primary key
class BRCategoryInt {
String lang
String name
static hasMany = [category: BRCategory]
static constraints = {
}
static mapping = {
table "brCategoryInt"
version false
//id column: ""
category column: "CategoryId"
lang column: "Lang"
name column: "Name"
}
}
In legacy database we have not primary key, just have an one FK CategoryId.
Any help will be very appreciated.
You should really always have a primary key on your data and I would recommend adding one just to keep everyone happy. If you cannot simply add a auto-increment id to your table you could use a composite key. See documentation here. If you cannot do this either then I would consider re-thinking how youe data is laid out.
You cannot map such domain in Grails. To read/write such legacy tables try groovy Sql.
It is my understanding that in theory it is possible to map to a table without a primary key, however I have yet to see it actually done. I have struggled with attempting it for days with nothing to show.
Short answer: Not possible in the current version of Grails.