Marten JasperFx - How to ignore property of class when document is generated - postgresql

Its possible ignore class property when Marten store document on database?
Eg.:
public class Test
{
public int Id { get; set; }
public string Name { get; set; }
[Ignore this when create a document on DB]
public Date DateOfBirth { get; set; }
}

SOLVED
public class Test
{
public int Id { get; set; }
public string Name { get; set; }
[IgnoreDataMember]
public Date DateOfBirth { get; set; }
}

TL:DR
Marten just uses Newtonsoft.Json under the hood, so to ignore property, use Newtonsoft JsonIgnoreAttribute:
public class Account
{
public string FullName { get; set; }
public string EmailAddress { get; set; }
[JsonIgnore]
public string PasswordHash { get; set; }
}
Explanation
This seems to be question visible on top of google search so I'd like to add my 50 cents.
Since MartenDB use internally Newtonsoft.Json then all attributes from this lib should work fine. I don't know about Igor answer, couldn't confirm this anywhere in library so it seems to be outdated at the moment.
From docs:
An absolutely essential ingredient in Marten's persistence strategy is JSON serialization of the document objects. Marten aims to make the JSON serialization extensible and configurable through the native mechanisms in each JSON serialization library. For the purposes of having a smooth "getting started" story, Marten comes out of the box with support for a very basic usage of Newtonsoft.Json as the main JSON serializer.
About Newtonsoft.json in MartenDB
MartenDB isn't tied to Newtonsoft.json, you could always write own adapter for other library.
All you have to do is implement ISerializer interface:
public interface ISerializer
{
void ToJson(object document, TextWriter writer);
string ToJson(object document);
T FromJson<T>(TextReader reader);
object FromJson(Type type, TextReader reader);
string ToCleanJson(object document);
EnumStorage EnumStorage { get; }
Casing Casing { get; }
CollectionStorage CollectionStorage { get; }
NonPublicMembersStorage NonPublicMembersStorage { get; }
}
More detailed example: docs

Related

including navigation property returning all records instead of just the property added

using EF Core code first approach i have my model setup like this
public class Author
{
public string Id{ get; set; }
public string Name{ get; set; }
public ICollection<Book> Books{ get; set; }
}
public class Book
{
public string Id{ get; set; }
public string Name{ get; set; }
public Author Author{ get; set; }
}
when i have to add an Author its simple. but when i have to add a Book i have to tell which author it belongs to.
DbSet = _context.Set<TEntity>();
public async Task<TEntity> GetAsync(string id, string include = null)
{
var query = DbSet.Include(include);
return await query.FirstOrDefaultAsync(x => x.Id == id);
}
using a code like this i first get the Author
public async Task<Book> AddBook(Book book, string authorId)
{
var author = await _authorRepo.GetAsync(authorId, "Books");
book.Id = Guid.NewGuid().ToString();
author.Books.Add(book);
_context.SaveChanges(); //(i have a reference to context here its a repository pattern)
return book;
}
So the problem is that when a book is returned a huge object is returned. a book that was added. and Author in that book and all the Books under that author. Any idea to return just the book that was added ?
any change in approach suggestion ?
I would suggest to create a separate Book repository where you could just work with books. This way you have more benefits like:
Separate logic for each type: author, book, etc.
Adding a book will not require you to retrieve the author first so less overload.
In general it's a best practice to separate business logic between different types of entities.
You can use JsonIgnoreAttribute to exclude a property from serialization:
public class Book
{
public string Id{ get; set; }
public string Name{ get; set; }
[JsonIgnore]
public Author Author{ get; set; }
}

Are there are any libraries that support user content localization in aspnetcore?

The are plenty of resources describing G11n an L10n in aspnetcore including the official docs.
But are there any libraries that simplify the implementation of a user content localization? An example could be a content of a blog post that may be translated into multiple languages. Such a library would use a specific table in SQL for storing/retrieving translation.
Here is the possible use case:
// this object contains content that user can add manually
public class BlogPost
{
// should be localised
public string Content { get; private set; }
}
It seems like we can add a collection of "string Content" in order to solve this issue:
public class LocalizableContent
{
public string CultureInfo { get; private set; }
public string Content { get; private set; }
}
public class BlogPost
{
public ICollection<LocalizableContent> Content { get; private set; }
}
Note: after making a bit of googling I found a related question (but it gives no answers):
Best Practices to localize entities with EF Code first | StackOverflow
Also, it doesn't seem like this library can help:
github.com/damienbod/AspNetCoreLocalization
Any suggestions?
I think you can implement your content localization library without the need to use third parties. Personaly I do something like below:
public class BlogPost {
public int Id { get; set; }
public ICollection<BloPostLocalized> Localizations { get; set; }
}
Create a localized class for BlogPost:
public class BlogPostLocalized {
public int Id { get; set; }
public BlogPostId { get; set; }
public BlogPost { get; set; }
public string Culture { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
Notice that the main BloPost has no Title nor Content fields, because we will have them defined in the BlogPostLocalized class for neutral and localized cultures.
So each blog post will have multiple localized versions that can be fetched simply from the db as a child of the main post.

Map custom DTO to breeze entities

Is it possible to map Flatened object to breeze entities? I have a DTO which is built up from multiple datasets but I am having trouble manipulating the data on the client. I would like the custom DTO to be part of the breeze metedata. below is a sample of the DTO.
Public class TimeKeepingItem
{
public int ClientId{ get; set; }
public string ClientName{ get; set; }
public string ClientSurname { get; set; }
public DateTime Date { get; set; }
public string Time { get; set; }
{
get { return Date.DayOfWeek.ToString(); }
}
}
Public class TimeKeepingContainer
{
public List<TimeKeepingItems> TimekeepingItems {get;set;}
//other properties
}
I would like to convert both the above classes to breeze entities on the client.
PW Kad's comment is correct, you can also take a look at the Edmunds and NoDb samples in the Breeze zip.

Circular Reference error when serializing objects in ASP.NET Web API

I'm writing a Web API project in C# that uses Entity Framework to pull data from a DB, serialize it and send it to a client.
My project has 2 classes, Post and Comment (foreign key from Post).
These are my classes.
Post class:
public partial class Post
{
public Post()
{
this.Attachment = new HashSet<Attachment>();
this.Comment = new HashSet<Comment>();
}
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public System.DateTime Created { get; set; }
public Nullable<System.DateTime> Modified { get; set; }
public virtual ICollection<Attachment> Attachment { get; set; }
public virtual ICollection<Comment> Comment { get; set; }
}
Comment class:
public partial class Comment
{
public int CommentId { get; set; }
public string Content { get; set; }
public System.DateTime Posted { get; set; }
public bool Approved { get; set; }
public int AnswersTo { get; set; }
public int PostId { get; set; }
public virtual Post Post { get; set; }
}
My problem is that when I try to get via Web API a Post, it spits me the following error:
Object graph for type 'APIServer.Models.Comment' contains cycles and cannot be serialized if reference tracking is disabled.
And when I try to get a Comment via Web API, the error is as follows:
Object graph for type 'System.Collections.Generic.HashSet`1[[APIServer.Models.Comment, APIServer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' contains cycles and cannot be serialized if reference tracking is disabled.
If I annotate the Comment class with
[DataContract(IsReference = true)]
the errors disappear, but the serialization only returns the ID of the comment and ignores the other fields.
Any suggestions on how to solve this?
Thanks in advance,
Léster
Here are 2 solutions
Solution #1:
I had this same problem and so I decorated my class with DataContract and the members with DataMember like you mention. HOWEVER, I don't like editing auto-generated code directly because I have to redo it every time I regenerate the file. In order to get around this, I used the MetadataType attribute. In your case, it would look like this...
First, you will keep the auto generated entity as is:
public partial class Comment
{
public int CommentId { get; set; }
public string Content { get; set; }
public System.DateTime Posted { get; set; }
public bool Approved { get; set; }
public int AnswersTo { get; set; }
public int PostId { get; set; }
public virtual Post Post { get; set; }
}
Next, in another file, you will create another partial class and decorate it like this:
[MetadataType(typeof(Metadata))]
[DataContract(IsReference = true)]
public partial class Comment
{
private class Metadata
{
[DataMember]
public int CommentId { get; set; }
[DataMember]
public string Content { get; set; }
[DataMember]
public System.DateTime Posted { get; set; }
[DataMember]
public bool Approved { get; set; }
[DataMember]
public int AnswersTo { get; set; }
[DataMember]
public int PostId { get; set; }
[DataMember]
public virtual Post Post { get; set; } // you can remove "virtual" if you wish
}
}
MetadataType will essentially add the attributes from the Metadata buddy class to the ones with the same name in Comment (not directly, but for our purposes, it's close enough... that's a topic for a different post). Of course, if your Comment entity changes, you'll need to update this accordingly.
Solution #2:
Having to edit your second file every time you make a change is only a slight improvement from directly editing auto-generated files. Fortunately, there is another approach that is much easier to maintain. Details can be found here but as a summary, all you need to do is decorate your OperationContract that is consuming Comment with an additional attribute, ReferencePreservingDataContractFormat. Note that there is a slight error in the code provided on that page that would cause infinite recursion. As noted in this post, the fix is quite simple: instead of recursing at all, just create a new DataContractSerializer
The advantage to this approach is that no matter how much you change Comment, you still don't need update anything.
As an example for your code, let's say you are using Comment as follows:
[OperationContract]
Comment FindComment(string criteria);
All you need to do is add
[OperationContract]
[ReferencePreservingDataContractFormat]
Comment FindComment(string criteria);
And then somewhere else you need to define ReferencePreservingDataContractFormat which will look like this:
//From http://blogs.msdn.com/b/sowmy/archive/2006/03/26/561188.aspx and https://stackoverflow.com/questions/4266008/endless-loop-in-a-code-sample-on-serialization
public class ReferencePreservingDataContractFormatAttribute : Attribute, IOperationBehavior
{
public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
{
}
public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy)
{
IOperationBehavior innerBehavior = new ReferencePreservingDataContractSerializerOperationBehavior(description);
innerBehavior.ApplyClientBehavior(description, proxy);
}
public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch)
{
IOperationBehavior innerBehavior = new ReferencePreservingDataContractSerializerOperationBehavior(description);
innerBehavior.ApplyDispatchBehavior(description, dispatch);
}
public void Validate(OperationDescription description)
{
}
}
class ReferencePreservingDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
public ReferencePreservingDataContractSerializerOperationBehavior(OperationDescription operationDescription) : base(operationDescription) { }
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes,
0x7FFF, //maxItemsInObjectGraph
false, //ignoreExtensionDataObject
true, //preserveObjectReferences
null //dataContractSurrogate
);
}
public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes,
0x7FFF, //maxItemsInObjectGraph
false, //ignoreExtensionDataObject
true, //preserveObjectReferences
null //dataContractSurrogate
);
}
}
And that's it!
Either method will work just fine--pick the one that works for you.
You can disable Lazy Loading on your Comment class by removing virtual from the Post property definition...
public partial class Comment
{
public int CommentId { get; set; }
public string Content { get; set; }
public System.DateTime Posted { get; set; }
public bool Approved { get; set; }
public int AnswersTo { get; set; }
public int PostId { get; set; }
public Post Post { get; set; }
}
This should sort out the circular reference exception.

Entity Framework and Models with Simple Arrays

This is my model class.
public class Lead
{
private readonly ObservableCollection<String> m_tags = new ObservableCollection<string>();
public int LeadId { get; set; }
public string Title { get; set; }
public ObservableCollection<String> Tags { get { return m_tags; } }
}
Does Entity Framework offer a way to represent this using either Model-First or Code-First?
EDIT: I'm looking for a way to do this without changing the public API of the model. The fact that there is some sort of Tags table shouldn't be visible to the downstream developer.
Since your model has to be represented in a relational way, you can only use primitive types (that have an equivalent in a SQL DB) or other entities within a entity definition - that means the tags are represented by their own entity. In your case it would be something like this using Code first approach:
public class Lead
{
public int LeadId { get; set; }
public string Name { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
public class Tag
{
public int TagId { get; set; }
public string Name { get; set; }
}
public class SomeContext : DbContext
{
public DbSet<Lead> Leads { get; set; }
public DbSet<Tag> Tags { get; set; }
}
This (by default) will be represented in the database as a table Leads, a table Tags, and a relationship table LeadTags that only contains {LeadId, TagId} pairs.