Persisting value objects in Typo3 - typo3

I've got a Money class that extends AbstractValueObject with the properties $amount (int) and $currency (string). And I've got an AbstractEntity with a $price property holding an instance of Money. How do I get Typo3 to persist that value object? How do I define the mapping?
Coming from Doctrine, I'd expect it to be persisted in two columns price_amount and price_currency.

Extbase does things a bit differently - so value objects needs to be stored in their own tables and relations between objects are stored by using identifiers just like entities.
The only real difference between Entities and VOs is that the persistence manager will use property values (except the identifier field) when looking for VOs for persistence whereas the identifier will be used on Entities.
So you need to add the database schema for the value object to ext_tables.sql and as the table should contain an auto incrementing uid field as well as the fields you need for your VO. Ensure that you create a combined unique index on the amount and currency columns.
Define the TCA mapping and then you can persist value objects either directly if you create a repository or by attaching them to aggregate root objects and persisting these.
The price property on your entity should be an integer in the database schema, as extbase will either store a reference to the uid of the VO (if you only refer to one Money object on your entity) and if you wish to store a collection of Money objects, Extbase will store the number of relations between your entity object and the Money VOs.

Related

Is there a way of allowing an end-user to modify enumeration values once application is released?

I am just starting out with CodeFluent and beginning to really like it. My question is: I set a property of an entity to enumeration. How can I allow an end-user to add extra values (that are stored afterwards as additional choices) to an enumeration? Or should I use another entity to store those values/choices instead?
For instance: let's say I have a product and a producttype. My producttype is an enumeration (frozen, fresh, seasonal), and down the road, the user wants additional types (i.e.: organic, stationary). Should those be enumeration values or a separate entity?
If a separate entity.....I'm not really sure how I define the relationship (1 to 1, 1 to many - i.e. 1 producttype can have many products)?
You can't add values to an enum at runtime, that's impossible in .NET, so it's also impossible with CodeFluent.
So, you want to create another entity that will store the list of enums. That would be a 1:M relation. This is how you would layout that relation:
Each enumeration value would be a row in the ProductType table. With CodeFluent, you can declare "instances" for an entity that will become rows in the final table, so here, you can declare your initial enum values using instance, so use the instance grid on the ProductType entity, and add instances:
Note in this case, maybe you want to create the ProductType's Id property as an int without identity (if you don't want those enum int values generated by the database).

entity framework "composite" property?

I am using EF 4.1, code first and want a property on a customer entity built up of a constant string value and the customerId zero padded to act as a customer reference.
I might be being a bit daft but am struggling to work out how I can achieve this without
A) having to savechanges twice, once to get the Id then set my reference and save again
B) having a partial Customer class that simply provides a getter returning constant + CustomerId.Tostring("000000")
Is this "doable" with code first?
If you can change the database I would make a computed column for this. Thus, you leave it to the database to generate a reference value and it will also be available to other consumers of the database (if any).
Your Customer class will have a property like CustomerReference (string) that maps to the computed column and that is configured to have DatabaseGeneratedOption.Computed which will cause EF to read the value after inserting an object.

Select Specific Columns from Database using EF Code First

We have a customer very large table with over 500 columns (i know someone does that!)
Many of these columns are in fact foreign keys to other tables.
We also have the requirement to eager load some of the related tables.
Is there any way in Linq to SQL or Dynamic Linq to specify what columns to be retrieved from the database?
I am looking for a linq statement that actually HAS this effect on the generated SQL Statement:
SELECT Id, Name FROM Book
When we run the reguar query generated by EF, SQL Server throws an error that you have reached the maximum number of columns that can be selected within a query!!!
Any help is much appreciated!
Yes exactly this is the case, the table has 500 columns and is self referencing our tool automatically eager loads the first level relations and this hits the SQL limit on number of columns that can be queried.
I was hoping that I can set to only load limited columns of the related Entities such as Id and Name (which is used in the UI to view the record to user)
I guess the other option is to control what FK columns should be eager loaded. However this still remains problem for tables that has a binary or ntext column which you may not want to load all the times.
Is there a way to hook multiple models (Entities) to the same table in Code First? We tried doing this I think the effort failed miserably.
Yes you can return only subset of columns by using projection:
var result = from x in context.LargeTable
select new { x.Id, x.Name };
The problem: projection and eager loading doesn't work together. Once you start using projections or custom joins you are changing shape of the query and you cannot use Include (EF will ignore it). The only way in such scenario is to manually include relations in the projected result set:
var result = from x in context.LargeTable
select new {
Id = x.Id,
Name = x.Name,
// You can filter or project relations as well
RelatedEnitites = x.SomeRelation.Where(...)
};
You can also project to specific type BUT that specific type must not be mapped (so you cannot for example project to LargeTable entity from my sample). Projection to the mapped entity can be done only on materialized data in Linq-to-objects.
Edit:
There is probably some misunderstanding how EF works. EF works on top of entities - entity is what you have mapped. If you map 500 columns to the entity, EF simply use that entity as you defined it. It means that querying loads entity and persisting saves entity.
Why it works this way? Entity is considered as atomic data structure and its data can be loaded and tracked only once - that is a key feature for ability to correctly persist changes back to the database. It doesn't mean that you should not load only subset of columns if you need it but you should understand that loading subset of columns doesn't define your original entity - it is considered as arbitrary view on data in your entity. This view is not tracked and cannot be persisted back to database without some additional effort (simply because EF doesn't hold any information about the origin of the projection).
EF also place some additional constraints on the ability to map the entity
Each table can be normally mapped only once. Why? Again because mapping table multiple times to different entities can break ability to correctly persist those entities - for example if any non-key column is mapped twice and you load instance of both entities mapped to the same record, which of mapped values will you use during saving changes?
There are two exceptions which allow you mapping table multiple times
Table per hierarchy inheritance - this is a mapping where table can contains records from multiple entity types defined in inheritance hierarchy. Columns mapped to the base entity in the hierarchy must be shared by all entities. Every derived entity type can have its own columns mapped to its specific properties (other entity types have these columns always empty). It is not possible to share column for derived properties among multiple entities. There must also be one additional column called discriminator telling EF which entity type is stored in the record - this columns cannot be mapped as property because it is already mapped as type discriminator.
Table splitting - this is direct solution for the single table mapping limitation. It allows you to split table into multiple entities with some constraints:
There must be one-to-one relation between entities. You have one central entity used to load the core data and all other entities are accessible through navigation properties from this entity. Eager loading, lazy loading and explicit loading works normally.
The relation is real 1-1 so both parts or relation must always exists.
Entities must not share any property except the key - this constraint will solve the initial problem because each modifiable property is mapped only once
Every entity from the split table must have a mapped key property
Insertion requires whole object graph to be populated because other entities can contain mapped required columns
Linq-to-Sql also contains ability to mark a column as lazy loaded but this feature is currently not available in EF - you can vote for that feature.
It leads to your options for optimization
Use projections to get read-only "view" for entity
You can do that in Linq query as I showed in the previous part of this answer
You can create database view and map it as a new "entity"
In EDMX you can also use Defining query or Query view to encapsulate either SQL or ESQL projection in your mapping
Use table splitting
EDMX allows you splitting table to many entities without any problem
Code first allows you splitting table as well but there are some problems when you split table to more than two entities (I think it requires each entity type to have navigation property to all other entity types from split table - that makes it really hard to use).
Create stored procedures that query the number of columns needed and then call the stored procs from code.

Entity framework 4 model first using money value object

I want to use a Money value object in my application. I have found several examples of a Money datatype. But I can't figure out how to use them with EF4. I would like to store each amount as a Decimal/CurrencyCode pair (where currencycode is a string - "USD", "SEK", etc) in the database. I tried creating a complexType but I couldn't get that to work. Is this possible?
It should be definitely possible. Your complex type is just pair of decimal and string property. It is exactly what complex type are used for. Depending on your approach you must do:
Database first:
You will define your database first. Your table will contain money and varchar columns representing your new type. When you update your EDMX model from database it will include it as scalar properties to your entity. You must remove those properties. Then go to model browser and create new complex type. Return back to entity and add complex property of your new complex type. And at the end you must go to entity mapping and map your complex type to those database columns.
Here is basic tutorial from MSDN but from unknown reason they didn't include such elementary details like screenshots. Here is some video from channel9.
Model first:
This is similar to database first but you don't have to deal with database creation and mapping. It will be generated for you.
Code first (EF 4.1):
You must create separate class for your complex type and use it as property in your entity. You should not need to map it by default - mapping should be infered. If it doesn't work you can map complext type either by using ComplextTypeAttribute annotation or by defining mapping in DbModelBuilder.
I can further extend approach you need to use if you provide more details.

Access the property used in mapping entity to a table in EFv4

When we have two entities in EFv4 EDM diagram and only one table for both in the database (for instance, having table Documents and entities Invoice and Qoute), table Documents having documentTypeId column as a discriminator and set this column as a discriminator in the EDM (in Table mappings), how do we read the value of this property in our code?
We cannot assign values to it because EF does it for us under the hood (based on what we entered in Table mappings for condition) but somehow I don't get it why we are also not allowed to read it.
Imo this property is already mapped so you can't map it again. It is used to determine type of materialized entity. Why do you need such column. Usually it is enough to use is operator like:
var document = context.Documents.GetById(id);
if (document is Invoice)
{
...
}
If you only need to select subtypes you can use OfType extension method like:
var invoices = context.Documents.OfType<Invoice>().ToList();
You also don't need to set this value when adding new entity because you are adding subtype - Invoice or Quote.
Edit:
As I understand from your comment you don't need this information in query. In such case you don't need to map it. Simply use partial class of your entity and add custom property which will return your string. Sound like stupid solution but actually it would be the easiest one.
Discriminator column should be part of mapping metadata so in case of T4 template generating your entities, it could be possible to update the template so it generate such property for you.
You may want to use a single-table inheritance hierarchy, as described here.
That way, you could have an abstract Document class that includes a DocumentTypeId column. Invoices and Quotes would extend this class, but specify certain DocumentTypeId filters. However, because the original class has a DocumentTypeId column, they would each have that column as well.
Another advantage to this approach is that you could create utility methods that can act on any Document, and you could pass any Invoice or Quote to these methods.