ASP.net Web API - Example pre-existing database Fluent NHibernate and Automapper - sql-server

I am working through the ASP.net Web API 2 book (Git Hub)
I am trying to use Fluent NHibernate and Automapper to connect to a database. The book uses a fresh database while my database is pre-existing and not necessarily controlled by good practices.
Before joining tables etc. I would like to just be able to get a list of people and add a new person via the API. The only catch is that I would like to return less properties of the actual table and create a new person with even less than the model used to display a new person. I am having trouble understanding the flow of the automapper.
An example table might be
<pre>Person Entity
-person_id(int)
-person_name(varchar(100))
-person_location(int)
-person_phone(varchar(10))
-person_address(varchar(30))
</pre>
The model I want to use includes a subset of the items in the actual table. For example, maybe:
<pre>Person Model
-person_id(int)
-person_name(varchar(100)
-person_location(int)</pre>
There is also a newPerson model
<pre>NewPerson Model
-Name
-location</pre>
I have an Entity with all the person properties like
public virtual int person_id {get;set;}
but I have a model with the subset properties like
public long person_id {get; set;}
In the automapping configuration file I have a class NewPersonToPersonEntityAutoMapperTypeConfigurator and I have another class PersonEntityToPersonAutoMapperTypeConfigurator
I'm confused about how automapper is working. Should the AutoMapper file NewPersonToPersonEntityAutoMapperTypeConfigurator use something like
Mapper.CreateMap<NewPerson, PersonEntity>
.ForMember(opt => opt.person_id, x => x.Ignore())
...
.ForMember(opt => opt.person_address(varchar(30)))
While
PersonEntityToPersonAutoMapperTypeConfigurator uses something like
Mapper.CreateMap<PersonEntity, PersonModel>
Can anyone show me a good example of a simple scenario like this with automapper and a pre-existing table with extra unused properties or describe what Automapper should be doing or if I am on the right track?

Daniel - I think you're on the right track. Yes, you need an AutoMapper map for each "direction"... i.e. incoming service message to the EF entity, and from the EF entity to the service return message.
Your code to ignore certain properties is fine. You just need to make sure the entity is populated appropriately for the INSERT into the database. For example, the person_id column - is that required to be set? Or is that an auto-incrementing column??
To say it another way... you can certainly use AutoMapper (and our approach in the book) against an existing database. It's still just mapping properties from one type to another type.
Feel free to send some code my way.

Related

Spring Data MongoDB - model classes without annotations

This question is related to Spring Data MongoDB model classes without annotations.
I have a situation where I need to store my domain classes either in RDBMS store or NoSQL store. Say for example my domain classes are User, Feature, PaymentRequest, Order, OrderLine, OrderHeader etc.
I cannot use any annotation on my domain classes for various reasons.
Application team will specify in which persistent store they like to store. They might configure to store it in MongoDB or in MySQL or in Oracle etc.
My requirement is when I am storing in MongoDB say using spring-data-mongodb I want to leverage the DBRefs for associated objects in my domain object.
How can I achieve with spring-data-mongodb without using annotations in my model classes.
class Role
{
String id;
String roleName;
}
class User {
String id;
String firstName;
String lastName;
List<Role> userRoles;
}
When I save User object I want to ensure that in MongoDB Role objects are stored as DBRefs instead of actual Role object graph.
My question is ─ without using annotations in my User and Role classes ─ how can I achieve this?
I searched the user's forums and could not find a way. That's why I'm posting my question here.
Thanks,
Kishore Veleti A.V.K.
Not sure if you ever figured this out, but you can use AspectJ to create an ITD (inter-type declaration) to weave in the annotations into the class without having to actually modify the original code.
For example, to turn your userRoles into a DBRef, you just need this aspect:
import org.springframework.data.mongodb.core.mapping.DBRef;
privileged aspect User_Mongo {
declare #field: * User.userRoles : #DBRef;
}
This simply adds the #DBRef annotation to any fields within User named userRoles. You can look at the AspectJ documentation for more information on field patterns and ITDs.

Do Fluent conventions break lazy loading? (uNhAddIns)

I have a simple entity class in a WPF application that essentially looks like this:
public class Customer : MyBaseEntityClass
{
private IList<Order> _Orders;
public virtual IList<Order> Orders
{
get { return this._Orders; }
set {this._Orders = new ObservableCollection<Order>(value);}
}
}
I'm also using the Fluent automapper in an offline utility to create an NHibernate config file which is then loaded at runtime. This all works fine but there's an obvious performance hit due to the fact that I'm not passing the original collection back to NHibernate, so I'm trying to add a convention to get NHibernate to create the collection for me:
public class ObservableListConvention : ICollectionConvention
{
public void Apply(ICollectionInstance instance)
{
Type collectionType =
typeof(uNhAddIns.WPF.Collections.Types.ObservableListType<>)
.MakeGenericType(instance.ChildType);
instance.CollectionType(collectionType);
}
}
As you can see I'm using one of the uNhAddIns collections which I understand is supposed to provide support for both the convention and INotification changes, but for some reason doing this seems to break lazy-loading. If I load a custom record like this...
var result = this.Session.Get<Customer>(id);
...then the Orders field does get assigned an instance of type PersistentObservableGenericList but its EntityId and EntityName fields are null, and attempting to expand the orders results in the dreaded "illegal access to loading collection" message.
Can anyone tell me what I'm doing wrong and/or what I need to do to get this to work? Am I correct is assuming that the original proxy object (which normally contains the Customer ID needed to lazy-load the Orders member) is being replaced by the uNhAddIns collection item which isn't tracking the correct object?
UPDATE: I have created a test project demonstrating this issue, it doesn't reference the uNhAddins project directly but the collection classes have been added manually. It should be pretty straightforward how it works but basically it creates a database from the domain, adds a record with a child list and then tries to load it back into another session using the collection class as the implementation for the child list. An assert is thrown due to lazy-loading failing.
I FINALLY figured out the answer to this myself...the problem was due to my use of ObservableListType. In NHibernate semantics a list is an ordered collection of entities, if you want to use something for IList then you want an unordered collection i.e. a Bag.
The Eureka moment for me came after reading the answer to another StackOverflow question about this topic.

Using NHibernate is it possible to create different database column(field) names based on language?

Something came up at work today and I'm not sure how you would go about it. Essentially, we have an application that is making use of NHibernate. Currently, we are using Fluent NHibernate and exporting the schema directly from the domain using ExportSchema. The column names are in English.
During some discussions today, it came out that as well as internationalizing the data there is an idea of getting the column names to be also in the language of the install.
So for example, if the database was deployed to an English speaking country the column names would be in English and if it was deployed to a francophone country the column names would be in French.
The theory seemed to be such that if a user wanted to write queries against the datastore they would be able to query using column names based in their native language. (assume they are named descriptively).
I can't say that I have come across this before and I am intrigued how you would go about it? Also, even though I mention NHibernate if there are other options please feel free to mention them.
Thanks
You could use resource files for each languauge you want to support and in your fluent mappings refer to these resources rather than hard coded strings. So an example mapping would looking something like this:
public OrderMap()
{
CultureInfo culture = CultureInfo.CurrentCulture;
ResourceManager rm = new ResourceManager("HelloWorldGlobed.myRes",typeof(OrderMap).Assembly);
DynamicUpdate();
Table(rm.GetString("ORDER_TABLE_NAME",culture));
Id(x => x.Id, rm.GetString("ORDER_ID",culture));
Map(x => x.Name, rm.GetString("ORDER_NAME",culture));
}
The above is just a simple example and I have not tested this but this gives you an idea of how you would do this using resources. You would probably want to consolidate the retriaval of the CultureInfo object and the ResourceManager object in a static class or something.
Here is also an example of using resources in C#:
http://www.codeproject.com/Articles/5208/MultiLanguage-Applications

How to use Yii with a multilingual database model?

I’m having a problem getting the data from my database which I created to be completely multilingual, and I hope someone here can help me.
I’ve split up all my tables in 2 parts; the “universal” table (does not contain any text that needs to be translated) and the table which contains all the fields that need to be translated with their translations.
Example tables:
base_material
id
picture
base_material_i18n
base_material_id
localization_id
name
description
review_status
review_notes
localization
id
language_name
Query to get the translations (using English (en) as a fall-back language if there is no translation available):
SELECT o.id
, o.type
, o.code
, o.position
, ifnull(t.name,d.name) name
, ifnull(t.description,d.description) description
FROM base_material o
INNER JOIN base_material_i18n d
ON ( o.id=d.base_material_id)
LEFT OUTER JOIN base_material_i18n t
ON ( d.base_material_id=t.base_material_id AND t.localization_id='nl' )
WHERE d.localization_id='en'
My question is how I can automatically get those translations (with the fall-back language as in this query) attached to my model in Yii when I’m searching for the base_material objects? (This is only 1 example table, but almost all my tables (20+) are built in this way, so if possible I would be needing something flexible)
An example of an existing system using what I would need is Propel: http://propel.posterous.com/propel-gets-i18n-behavior-and-why-it-matters
Any ideas how to go about doing that? I’ve checked the existing Yii extensions regarding multilingual sites (like Multilingual Active Record), but they all use a different database design (general information+fall-back language in the main table, translations in the i18n table), and I’m not sure how to change those extensions to use my kind of DB model.
If someone knows of a way to change that existing extension so it can use my kind of DB scheme, then that would be absolutely brilliant and probably the best way to do this.
Edit: I've added a bounty because I still can't find anything on how to let Propel work with Yii (there does exist an extension for Doctrine, but Doctrine doesn't support this kind of DB model with translations either), nor any more information as to how to deal with this using an existing Yii extension or with scopes.
Edit: 98 times viewed but only 3 upvotes and 1 comment. I can't help feeling like I'm doing something wrong here, be it in my question or application/database design; either that or my problem is just very unique (which would surprise me, as I don't think my multilingual database design is that absurd ;-). So, if anyone knows of a better all-round solution for multilingual sites with Yii and/or Propel (apart from the current extensions which I really don't like due to the duplication of text fields) or something similar, please let me know as well.
Thanks in advance!
Have you tried http://www.yiiframework.com/extension/i18n-columns/ (based on http://www.yiiframework.com/extension/stranslateablebehavior/)?
It is an alternate, simpler, approach by adding new table fields in the style of {field}_{language code}, and then setting the translated field in the original model to the current language's translation on afterFind.
In essence, it will get you up and running with translatable fields with the translated content being fetched "automatically", for good and bad :). Adding and removing languages (=columns) is done using migrations.
I am also looking for a generic solution to implement i18n into Yii models.
Recently I chose a very similar database schema for a project like you.
The only difference is, that I am not using a separate language table, I store the language information in the i18n table.
The following solution is without a custom SQL statement, but I think this could be implemented with relation params, anyway, if you're working with foreign key in your database (eg. MySQL InnoDB) gii will create relations between your base_material and base_material_i18n table, like
class BaseMaterial extends CActiveRecord
public function relations()
{
return array(
'baseMaterialI18ns' => array(self::HAS_MANY, 'base_material_i18n', 'id'),
);
}
class BaseMaterialI18n extends CActiveRecord
public function relations()
{
return array(
'baseMaterial' => array(self::BELONGS_TO, 'base_material', 'id'),
);
}
Now you'd be able to access your translations by using the object notation for relations.
$model = BaseMaterial::model()->with('baseMaterialI18ns')->findByPk(1);
foreach($model->baseMaterialI18ns AS $translation) {
if ($translation->language != "the language I need") continue:
// do something with translation data ...
}
I thought about creating a behavior or base class for those models which would act a as helper for managing the translations - pseudo code:
I18nActiveRecord extends CActiveRecord
protected $_attributesI18n;
// populate _attributesI18n on query ...
public function __get($name) {
if(isset($this->_attributesI18n['language_I_need'][$name]))
return $this->_attributesI18n[$name];
else if(isset($this->_attributesI18n['fallback_language'][$name]))
return $this->_attributesI18n[$name];
else
parent::__get();
}
CActiveRecord __get() source
There is more work to be done to find the needed i18n record, also you could further limit the with() option to improve performance and reduce parsing on the PHP side.
But there may be different use cases how to determine the value, e.g. all translations, translation or fallback, no fallback (empty value).
Scenarios could be helpful here.
PS: I would be up for a github project!
You can try to use a simple multilingual CRUD extension.
it is very simple to use and modificate. you just need to add language field to your table.
just watch description here: http://all-of.me/yii-multilingual-crud/
it is in alpha state, but tried on a few projects. you can easily modificate it or contact author to fix or add features

Silverlight / .NET RIA Services - Exposing a custom property to the client

I have a table in my database called "Task". Task has the following fields:
- ID
- Description
- AssignedUserID
- TaskTypeID
I am accessing this table through a class that was created automatically after I used an ADO.NET Entity Data Model. I can load and show the fields mentioned above in a DataGrid in my Silverlight application. However, AssignedUserID and TaskTypeID are not very descriptive. So I decided to create a stored procedure that gets the tasks and the user and task type names through their respective lookup tables. This is where the problem lies.
I want to create some custom properties in the automatically generated "Task" class. The custom properties would be named "AssignedUserName" and "TaskType". I then want to make these properties available to my Silverlight client. However, I cannot seem to figure out how to get them exposed to my Silverlight client.
Can someone help?
Thank you
If your EDM is in the same project as the DomainService you can do this:
create a partial class on the Entity type, and add your calculated property in there.
name the file **.shared.cs
it will then be auto-shared with the client/Silverlight code.
Edit:
I was assuming that you could do this calculation in app logic rather than use an sp, which seems more straightforward to me.
If you do use an SP, you'll need to use the Function Import feature in the designer to map the SP to a function in the EDM. This function can then return entities, with properties mapped however you like.
An easier way would be to just use the object model: Have Task.AssignedUser and Task.TaskType objects off of your Task class. Map these to lookup tables in your db. This will work out-of-the box (assuming the Id's are FK's to those lookup tables).
So, a couple options:
use app-logic--properties in a partial class to return the descriptions
use the object model driven by FKs to lookup tables, then just access Task.AssignedUser.Name or Task.TaskType.Description
use a function import to access the SP and map the returned values to entity properties
1 or 2 being the best options IMHO.
Another approach might be to update your EF model to include the lookup tables, add Associations between the tables, add [Include]s in the (auto-gen'd) metadata class and let EF and RIA do it for you. Maybe.

Resources