I'm using the Azure Mobile Service for a Windows Phone 8 project.
I am trying to store complex types in my database and therefore use json.net's JsonConverter.
My data-class looks like this:
public class Data
{
...
[JsonConverter(typeof(MyConverter))]
public ComplexType SomeMember{get;set;}
...
}
That seems to work fine, but there is one problem:
I want to map the 'Data'-class to a database table with a different name, like 'data_something'
This can be achieved by using
[DataContract(Name="data_something")]
public class Dat
{
...
}
But then the Json.NET Annotations are ignored.
Is there a way to use Json.NET and specify the Table-Name separately?
Or perhaps another way to use Azure Mobile to get the right table even if the class name is not the same. (I'm currently using dataTable= MobileService.GetTable<Data>();)
You can use the [DataTable] attribute for that:
[DataTable("data_something")]
public class Data
{
[JsonConverter(typeof(MyConverter))]
public ComplexType SomeMember { get; set; }
// other members ommitted
}
Related
I've got a POCO defined, something like this:
public class Customer
{
public string Name { get; set; }
public DateTime DOB { get; set; }
[System.ComponentModel.DataAnnotations.Schema.NotMapped] // <- this is what I want to do, but can't in PCL
public AccountCollection Accounts { get; set; }
}
The above has the "NotMapped" attribute, which is what I want - but it's not available in a portable class library (PCL). The thing is, the class I need is defined in an assembly that WILL be used on the portable device but it will be filled from entity framework on the web, which DOES have access to the NotMapped attribute. If I could find a way to add the property to EF's "NotMapped" list, that would be ideal.
Is there a way to get this to work? That is, a way to do what "NotMapped" does programmatically?
I've considered other workarounds, but none of them are ideal:
Could create a DAL separate from my domain layer and translate
between the two (but requires mapping and two models instead of one)
Could write custom EF queries and updates to ignore the property (but means writing all the linq/SQL/procs myself)
Found the answer in the Context's OnModelCreating() overload. Accessing the modelBuilder parameter it's possible to find the entity and ignore specific properties. This works even when the POCO is defined in a PCL.
For example:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Ignore Customer.Accounts
modelBuilder.Entity<Customer>().Ignore(c => c.Accounts);
}
I've seen a lot of Kundera examples where the object being store is fairly simple. You have something like a Car.class and it contains a couple String variables maybe an int mapped using the #Column annotation. I've even seen some List, Set and Map variables as well as the cqlsh to create a column of those types.
What I haven't seen is a custom object I created within an object and how that would be represented in a Cassandra DB.
For example:
public Class ContainerShip {
#Column(name="container")
Container myContainer;
}
public Class Container {
#Column(name="containerName)
String containerName;
}
Could I store ContainerShip into Cassandra, using Kundera with em.persist(myShip)?
If I can what would the cqlsh for creating the "container" column look like?
You may embed a container object as an embeddable entity.
#Entity
public Class ContainerShip {
#Column(name="container")
#Embedded
Container myContainer;
}
#Embeddable
public Class Container {
#Column(name="containerName)
String containerName;
}
I have the following Domain Model:
public class DaybookEnquiry : Entity
{
public DateTime EnquiryDate { get; set; }
[ForeignKey("EnquiryType")]
public int DaybookEnquiryTypeId { get; set; }
public string AccountNumber { get; set; }
[ForeignKey("User")]
public int UserId { get; set; }
#region Navigation Properties
public virtual User User { get; set; }
public virtual DaybookEnquiryType EnquiryType { get; set; }
public virtual ICollection<DaybookQuoteLine> QuoteLines { get; set; }
#endregion
}
This is inside of a project named DomainModel. Entity is just a base class which my domain models inherit from, it contains an Id field.
I then have other projects inside my solution called ServiceInterface and ServiceModel. ServiceInterface contains all my services for my application and ServiceModel contains my DTO's and routes etc.. I'm trying to follow the guidelines set out here: Physical Project Structure
My EnquiriesService contains a method to create a new enquiry in my database using a repository:
public void Post(CreateEnquiry request)
{
// Not sure what to do here..
// _repository.Insert(request);
}
My CreateEnquiry request looks like so:
[Api("POST a single Enquiry for Daybook.")]
[Route("/enquiries", "POST")]
public class CreateEnquiry : IReturnVoid { }
As you can see, the CreateEnquiry request object is empty. Do I need to add properties to it to match my Domain Model and then use AutoMapper or something similar to map the fields to my Domain Model and pass that into my repository?
The Insert method on my repository looks like so:
public virtual void Insert(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Detached)
{
dbEntityEntry.State = EntityState.Added;
}
else
{
DbSet.Add(entity);
}
DbContext.SaveChanges();
}
Yes. Your Service request, in this case CreateEnquiry needs to have all the properties you need in order to do whatever it is you want to do!
I've seen two different models for Create vs Update:
Use one request objects called, say, SetEnquiry that has a nullable id field. When null and using the POST HTTP verb, it internally creates a new object. And when not null and using the PATCH HTTP verb, it internally updates an object. You can use ServiceStack's implementation of AbstractValidator<T> to add logic such as if POST then id field needs to be null; and if PATCH then id field cannot be null. This will help ensure your data is always as it needs to be.
Create two request objects -- one for Create and one for Update. The Create doesn't even have an id field, and the Update has one and requires it. You can use the same validation technique used above, except applied to each class independently, so you don't need the conditional check of if this verb do this; if that verb do that.
How you map to your data model is up to you. You can use something like AutoMapper or you can use ServiceStack's built-in TranslateTo and PopulateWith methods. I personally take a middle ground: I created my own object extension methods called MapTo and MapFrom that interally call TranslateTo and PopulateWith respectively. Why did I do this? Because then I control those extensions inside my own namespaces and when I need to do special mappings (like a column name doesn't match up, or one object is more complex than the other, or I simply want to ignore a particular column from one of the objects) I simply overload the MapTo and MapFrom with explicit types, giving it higher specificity than the generic methods.
So back to your question specifically. Assuming you're using the built in TranslateTo your service method might look like this:
public void Post(CreateEnquiry request)
{
_repository.Insert(request.TranslateTo<Enquiry>());
}
One more thing: I generally return the object itself when doing a Create and Update. As fields can change (auto-calculated fields, for example) I like to return the object back to the caller. This is preference and has no real bearing on the answer I'm giving you. Just throwing it out there!
I have created a custom control with a collection property per the example on How do you build an ASP.NET custom control with a collection property?
When the control is added to a common ASP.Net aspx page it works as expected. However, when added to a Page Layout in Sharepoint the following error is thrown:
Unable to cast object of type 'System.Web.UI.CollectionBuilder' to type 'System.Collections.Generic.List`1[mytypes.mytype]'.
The code is pretty much identical to the code provided by the example shown in the link above. I do not think the fault lies in the control as it works fine in a plain web project.
I dont think you can use generic lists in sharepoint. Use an ArrayList or customised List collection instead (use asp:ListItem as an exampe, it has its own collection type)
[ParseChildren(true, "Names")]
public class MyControl : Control {
private List<PersonName> names;
public MyControl() {
names = new List<PersonName>();
}
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public List<PersonName> Names {
get { return this.names; }
}
}
public class PersonName {
public string Name { get; set; }
}
UPDATE
Ahh i see the problem now, it is not to do with the generic list, it is because of the way you are doing the initialization.
Create a private variable to hold the list private List<PersonName> names;
Ensure that the property does not have a setter
My table:
create table MyTable (
Id int identity(1,1) not null,
MyStatus char(2) not null
)
insert into MyTable(MyStatus) select 'A'
Class and enum:
public class MyTable
{
public virtual int Id { get; set; }
public virtual MyTableStatus MyStatus { get; set; }
}
public enum MyTableStatus
{
A,
B
}
Mapping:
public MyTableMap()
{
Id(x => x.Id);
Map(x => x.MyStatus);
}
When I execute the following test, I get System.FormatException : Input string was not in a correct format...
[Test]
public void Blah()
{
MyTable myTable = Session.Get<MyTable>(1);
Assert.That(myTable.MyStatus, Is.EqualTo(MyTableStatus.A));
}
What is the right way to map an enum to it's string representation in the database?
Edit - I am writing my application on an existing database, which I cannot modify easily because it is used by other applications also. So some fields in the database (which I would like to represent as enums in my application) are of type int and some of type char(2).
You need to create a custom IUserType to convert an enum to its string representation and back. There's a good example in C# here and an example in VB.NET for working with enums here (scroll down to implementing IUserType).
Well as far as I am aware NHibernate stores enums as string only in the db by default. I think I know what the problem here is. The way you are creating the table is incorrect.
if you are using Nhibernate use it build configuration function to create the tables instead of creating the tables manually and then you will see that your enum is stored as string.
We use enums extensively in our app and it makes sense for us to store it as strings in the db. The reasons are simple if I add a new value to an enum tom then if default values are not set then my code and my data are tightly coupled which I definitely wouldnt want.
SimpleConfig.ExposeConfiguration(c => new SchemaExport(c).Create(false, true)).BuildConfiguration();
Also instead of using char for your string can you use varchar for the property.
After the update:
Cant you guys do some kind of manipulation before you store it in the database? Thus when you want to store the new char enums write a function that generates an int value for you and store this in the propertry and now save it or if you want to make it simple the function can have a switch case.
So what you do is you dont have a get on this property that is retrieved from the db instead you add a new property in the class Status that basically has the logic of getting the appropriate enum.
Do you think thats a good idea?
Hope this helps.