We're working with Fluent NHibernate 1.2 and our primary key is a guid saved in a nvarchar(32) column, working with Oracle 11gr2.
How can we make this work? (making an automatic conversion...)
Thanks ahead, random programmer...
UPDATE:
forgot to mention, the guid is saved WITHOUT dashes ...
Update:
You will have to implement your own IUserType to handle the dashless Guids.
You can read about it here:
http://dotnet.dzone.com/articles/understanding-nhibernate-type
The detail below is now irrelevant to the question but I'll keep it here for future reference for people to find.
Using Guids "normally"
In your entity the Id should be of type Guid:
public virtual Guid Id { get; private set; }
And in your ClassMap you should map it like this:
Id(x => x.Id)
.Column("Id")
.GeneratedBy.GuidComb();
This will use the recommended comb algorithm to generate new guids.
or
Id(x => x.Id)
.Column("Id")
.GeneratedBy.Guid();
to genertae new Guids using System.Guid
or
Id(x => x.Id)
.Column("Id")
.GeneratedBy.GuidNative();
if you want to let the database generate the Guid for you.
Related
In my request data, if I have a duplication Guid ID, I want to generate a new Guid ID automatically. How to do it?
public class Roster { public Guid Id {get; set;} }
Here Guid Id is the primary key.
When I made an api post request, what would be the value I give for Guid Id?
If you use SQL and EntityFramework Core you could use this inside your model:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ActivityId { get; set; }
This will tell EF:
this property is the PRIMARY KEY of the table hence the [KEY]
this property should be automatically generated by the database
FYI you need to set a DEFAULT value for you SQL column like so:
(newsequentiaid()) tells SQL that he's in charge of creating a Globally Unique Id everytime you add a record to that table
Don't know if this is the answer you were looking for (nex time provide more info for us) anyway
hope this helps you Cheers!
UPDATE
I do not know if my solution works with MySQL i use it for SQL. Searching a bit online i found no resources to newsequentialid in MySQL database (but i could be wrong, do your own research if you'd like).
Anyway i just don't set it for example:
var activityDB = await context.Activity.FirstOrDefaultAsync(c => c.ActivityId == activity.ActivityId);
if (activityDB == null)
{
activityDB = new Activity();
context.Activity.Add(activityDB);
}
activityDB.Code = activity.Code;
activityDB.Description = activity.Description;
activityDB.Status = activity.Status;
Here's what the code does
check if my id exists if yes i have to edit if is null i don't
create new activity and edit
automatically EF nows what id to handle therefore no need to se it
If there is it means im editing for that id if not will create it automatically
Following this article (What are best practices for multi-language database design?), I have all my database tables splitted in two: the first table contains only language-neutral data (primary key, etc.) and the second table contains one record per language, containing the localized data plus the ISO code of the language. The relationship between the two tables is one to many.
Here a screenshot of the datamodel: https://dl.dropboxusercontent.com/u/17099565/datamodel.jpg
Because the website has 8 languages, for each record in table "CourseCategory" I have 8 record in table "CourseCategoryContents". The same happens with "Course" and "CourseContent"
Then I use Entity Splitting in order to have only one entity for the Course Category and one entity for the Course:
public class CourseCategoryConfiguration : EntityTypeConfiguration<WebCourseCategory>
{
public CourseCategoryConfiguration()
{
Map(m =>
{
m.Properties(i => new { i.Id, i.Order, i.Online });
m.ToTable("CourseCategories");
});
Map(m =>
{
m.Properties(i => new { i.LanguageCode, i.Name, i.Permalink, i.Text, i.MetaTitle, i.MetaDescription, i.MetaKeywords });
m.ToTable("CourseCategoryContents");
});
}
}
public class CourseConfiguration : EntityTypeConfiguration<WebCourse>
{
public CourseConfiguration()
{
Map(m =>
{
m.Properties(i => new { i.Id, i.CategoryId, i.Order, i.Label, i.ThumbnailUrl, i.HeaderImageUrl });
m.ToTable("Courses");
});
Map(m =>
{
m.Properties(i => new { i.LanguageCode, i.Name, i.Permalink, i.Text, i.MetaTitle, i.MetaDescription, i.MetaKeywords, i.Online });
m.ToTable("CourseContents");
});
}
}
Then to retrive the courses in a desired language including their category I do this:
using (WebContext dbContext = new WebContext())
{
// all courses of all categories in the desired language
return dbContext.Courses
.Include(course => course.Category)
.Where(course => course.LanguageCode == lan
&& course.Category.LanguageCode == lan)
.ToList();
}
}
Entity splitting works fine with one-to-one relationships, but here I have one-to-many relationships.
The website has contents (CourseCategories and Courses) in 3 languages ("en", "de", "fr").
EF correctly returns all the Courses with their Category in the right language (eg. in english), but returns each record 3 times. This is because I have the CourseCategory in 3 languages too.
The only one working solution I came up is avoiding using ".Include(Category)", getting all the courses in the desired language in first, then, in a foreach cycle, for each Course retriving its Category in language. I don't like this lazy loading approach, I would like to retrive all the desired data in one shot.
Thanks!
The best solution is to map tables to the model as it then in your model Course class will have a navigation property ICollection<CourseCategoryContent>.
In this case you just project this model to DTO or ViewModel "according to your application design"
e.g.
Your model will look like this
public class Course
{
public int Id {get; set;}
public int Order {get; set;}
public ICollection<CourseCategoryContent> CourseCategoryContents {get; set;}
}
public class CourseCategoryContent
{
public string LanguageId {get; set;}
public string Name {get; set;}
}
Then just create new DTO or ViewModel like :
public class CourseDTO
{
public int Id {get; set;}
public int Order {get; set;}
public string Name {get; set;}
}
Finally do the projection
public IQueryable<CourseDTO> GetCourseDTOQuery ()
{
return dbContext.Courses.Select(x=>new CourseDTO{
Id = x.Id,
Order = x.Order,
Name = x.CourseCategoryContents.FirstOrDefault(lang => lang.LanguageId == lang).Name,
});
}
And note that the return type is IQueryable so you could do any filter, Order or grouping operation on it before hitting the database.
hope this helped
No fix-all answer i'm afraid, every way has a compromise.
I've used both the database approach (10+ language dependent tables) and the resource file approach in fairly large projects, if the data is static and doesn't change (i.e you don't charge a different price or whatever) I would definately consider abstracting language away from your database model and using Resource keys then loading your data from files.
The reason or this is the problem you are experiencing right now where you can't filter includes (this may have changed in EF6 perhaps? I know it's on the list of things to do). You might be able to get away with reading it into memory and filtering them though like you're doing but this meant it wasn't very performant for us and I had to write Stored Procedures that I just passed the iso language and executed in EF.
From a maintenance point of view it was easier as well, for the DB project I had to write an admin console so people could log on and edit values for different languages etc. Using resource files I just copy-pasted the values into excel and emailed them to the people we use to translate.
It depends on the complexity of your project and what you prefer, i'd still consider both approaches in future.
TLDR: options that i've found are:
1) filter in memory
2) lazy load with filter
3) write stored procedure to EF and map that result
4) use resources instead
Hope this helps
EDIT: After looking at diagram it looks like you may need to search against the language dependant values? In that case resources probably won't work. If you're just letting them navigate off a menu then you're good to go.
Here is my issue.
I have a customer table and an address table. The customer table has two foreign keys to the address table. ShippingAddressFK and BillingAddressFK
Normally I'd just have AddressFK if it was just one foreign key. But since it's two I'm not sure how to go about it.
I saw this:
Fluent Nhibernate AutoMapping -- 2 foreign keys to same table?
But I'm not sure how to translate that to the Sharp Lite Architecture override .cs file.
In the MyStore example this was the closest I could find:
public class OrderOverride : IOverride
{
public void Override(ModelMapper mapper) {
mapper.Class<Order>(map => map.Property(x => x.OrderStatus,
status => {
status.Type<OrderStatusCustomType>();
status.Column("OrderStatusTypeFk");
}));
}
}
I notice they are similar I'm just not sure how to change the solution above to fit this sort of override class in the Sharp Lite Architecture
No access to visual studio so haven't tried this out, consider psuedo code based on the code you pasted and the code in the other question you linked to:
public class CustomerOverride : IOverride
{
public void Override(ModelMapper mapper) {
mapper.Class<Customer>(map => map.Property(x => x.BillingAddress,
address => {
address.Type<Address>();
address.Column("BillingAddressFk");
}));
mapper.Class<Customer>(map => map.Property(x => x.ShippingAddress,
address => {
address.Type<Address>();
address.Column("ShippingAddressFk");
}));
}
}
I just had a look at Order override in SharpLite and this isn't fluent nhibernate, it is nhibernate code mapping which I have never used. that might not be the correct way to define multiple property overrides but hopefully the code above will work. if not change the fluentnhibernate tag to nhibernate and some1 who knows more about it should be able to help.
The example you are referring to is for mapping one of your properties to a custom type, like an Enum.
You need to map your relationship to the multiple addresses, and give it a different column name than what your conventions would.
public void Override(ModelMapper mapper)
{
mapper.Class<Customer>(map =>
map.ManyToOne(
x => x.BillingAddress,
x => x.Column("BillingAddressFk")));
mapper.Class<Customer>(map =>
map.ManyToOne(
x => x.ShippingAddress,
x => x.Column("ShippingAddressFk")));
}
Notice the ManyToOne instead of Property.
I have an entity and its mapping:
public class Test
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
}
public class TestMap : EntityMap<Test>
{
public TestMap()
{
Id(x => x.Id);
Map(x => x.Name);
Map(x => x.Description);
}
}
I'm trying to run a query on it (to grab it out of the database):
var keyword = "test" // this is coming in from the user
keyword = keyword.ToLower(); // convert it to all lower-case
var results = session.Linq<Test>
.Where(x => x.Name.ToLower().Contains(keyword));
results.Count(); // execute the query
However, whenever I run this query, I get the following exception:
Index was out of range. Must be non-negative and less than the size of the
collection. Parameter name: index
Am I right when I say that, currently, Linq to NHibernate does not support ToLower()? And if so, is there an alternative that allows me to search for a string in the middle of another string that Linq to NHibernate is compatible with? For example, if the user searches for kap, I need it to match Kapiolani, Makapuu, and Lapkap.
I had this happen recently. I can tell you that ToLower() does not work and that Contains() and StartsWith() do work and are not case sensitive. You can get the desired affect by using Contains() and StartsWith() directly.
There seems to be a lot of confusion around this subject.
The "old" Linq provider (for NHibernate 2.x) probably might not support this. If that's the case, it never will because it's not maintained anymore.
The new provider (included with NHibernate 3.x) does support it (although ToUpper and ToLower seem to be inverted, see http://groups.google.com/group/nhibernate-development/browse_thread/thread/a167216e466b3241)
Contains and StartsWith map to the LIKE operator in SQL. They are not case insensitive themselves; it's the collation that makes them case insensitive, so that depends on how your column/schema were created.
Update (2010-04-09): bug confirmed and patch submitted, see https://nhibernate.jira.com/browse/NH-2169
Update (2010-05-21): patch was applied on 2010-05-01 and works as expected now.
According to the comments in these two blog posts this functionality is not implemented yet.
You might want to confirm whether the database uses case sensitivity.
If it doesn't, then you don't need .ToLower()
The accepted answer mentions using Contains() and StartsWith() which are good. but wouldn't work in cases when you want to be sure both strings are the same.
Using "==" will suffice since it is also case-insensitive. So, you no longer need to use ToLower() nor ToUpper();
I have an application where the identity column is stored as an Oracle VARCHAR2(50 BYTE) but is actually a Guid. I want my model to expose it as a Guid:
class Foo
{
public Guid Id { get; set; }
}
Using Fluent NHibernate I don't see a CustomTypeIs() method on the IIdentityPart. I would think it would be something similar to an IUserType, but I can't find the correlation. Any thoughts?
Fabio Maulo noted that this is governed by the DataProvider on the NHibernate Users mailing list.