Azure, DocumentDB cannot save POCO object as a document - azure

I have serious problem with MS Azure DocumentDB.
I Know it's in pre-realese only, but as I know it is said that it is possible to save Dynamic and POCO objects as a documents. When I save dynamic object it works just fine (object is added to a collection):
dynamic dynamicObject = new
{
testId = "12",
text = "aaa bbb ccc"
};
await client.CreateDocumentAsync(collectionSelfLink, dynamicObject);
However, when I try to add a POCO obejct, it doesnt works (nothing is added to a collection):
public class House
{
[JsonProperty(PropertyName = "id")]
public string HouseId { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "address")]
public string Address { get; set; }
}
------------------
House house = new House() {HouseId = "1", Name="TestHouse", Address="asdasdasd"};
await client.CreateDocumentAsync(collectionSelfLink, house);
Everything else is the same.
EDIT: temp solution is to inherit your POCO class from Microsoft.Azure.Documents.Document class.

as per my comment, can't repro this.
here is my test project:
static void Main(string[] args)
{
House house = new House() { HouseId = "1", Name = "TestHouse", Address = "asdasdasd" };
Document doc = client.CreateDocumentAsync(col.DocumentsLink, house).Result;
Console.Write(doc.SelfLink);
Console.ReadLine();
}
public class House
{
[JsonProperty(PropertyName = "id")]
public string HouseId { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "address")]
public string Address { get; set; }
}
results in 1 document created and doc.selfLink being printed to the Console.

Related

MVC inserting values into a ViewModel after Model to ViewModel mapping

I am working with two different databases. I am passing the Model collection (SQL Server) to a ViewModel collection. The ViewModel has extra properties which I access out of a Visual Fox Pro database. I am able to map the existing properties, but the ViewModel does not save the data after passing the values to it.
The WoCust and the Lname fields return null, but the rest of the properties which come from the original Model pass to the properties in the ViewModel fine.
When I debug at the rdr for the OleDbCommand, it shows that the ViewModel is receiving a value for both rdr[WoCust] and rdr[Lname].
How do I make it so the ViewModel saves the new values?
WOSchedule.cs...
public partial class WOSchedule
{
public long Id { get; set; }
public string WoNo { get; set; }
public Nullable<long> QuoteTypeId { get; set; }
public Nullable<int> PriorityNo { get; set; }
public bool Active { get; set; }
public Nullable<System.DateTime> WoDate { get; set; }
public Nullable<long> QuoteID { get; set; }
public Nullable<System.DateTime> WoDone { get; set; }
public Nullable<long> WOScheduleListId { get; set; }
public string StorageLocation { get; set; }
public virtual QuoteType QuoteType { get; set; }
public virtual Quote Quote { get; set; }
public virtual WOScheduleList WOScheduleList { get; set; }
}
WoWcheduleVM.cs...
public partial class WoScheduleVM
{
public long Id { get; set; }
public string WoNo { get; set; }
public Nullable<long> QuoteTypeId { get; set; }
public Nullable<int> PriorityNo { get; set; }
public bool Active { get; set; }
public DateTime? WoDate { get; set; }
public Nullable<long> QuoteID { get; set; }
public DateTime? WoDone { get; set; }
public Nullable<long> WOScheduleListId { get; set; }
public string StorageLocation { get; set; }
public string WoCust { get; set; } // extra property
public string Lname { get; set; } // extra property
public virtual QuoteType QuoteType { get; set; }
public virtual Quote Quote { get; set; }
public virtual WOScheduleList WOScheduleList { get; set; }
}
WOSchedulesController.cs
string cs = ConfigurationManager.ConnectionStrings["foxproTables"].ConnectionString;
OleDbConnection cn = new OleDbConnection(cs);
var wOSchedules = db.WOSchedules.Where(w => w.WoDone == null).Include(w => w.QuoteType);
var wOSchedulesVM = wOSchedules.Select(s => new ViewModels.WoScheduleVM()
{
Id = s.Id,
WoNo = s.WoNo,
QuoteTypeId = s.QuoteTypeId,
PriorityNo = s.PriorityNo,
Active = s.Active,
WoDate = s.WoDate,
QuoteID = s.QuoteID,
WoDone = s.WoDone,
WOScheduleListId = s.WOScheduleListId,
StorageLocation = s.StorageLocation
});
cn.Open();
foreach (var sch in wOSchedulesVM)
{
string conn = #"SELECT wo_cust, lname FROM womast INNER JOIN custmast ON womast.wo_cust = custmast.cust_id WHERE wo_no = '" + sch.WoNo + "'";
OleDbCommand cmdWO = new OleDbCommand(conn, cn);
OleDbDataReader rdr = cmdWO.ExecuteReader();
while (rdr.Read())
{
sch.WoCust = ((string)rdr["wo_cust"]).Trim();
sch.Lname = ((string)rdr["lname"]).Trim();
}
}
cn.Close();
return View(wOSchedulesVM.OrderByDescending(d => d.WoDate).ToList());
The problem is you're using foreach loop for iterating wOSchedulesVM collection, which renders the source collection immutable during iteration. The older documentation version explicitly explains that behavior:
The foreach statement is used to iterate through the collection to get
the information that you want, but can not be used to add or remove
items from the source collection to avoid unpredictable side effects. If you need to add or remove items from the source collection, use a for loop.
Therefore, you should use for loop to be able to modify property values inside that collection, as shown in example below:
using (var OleDbConnection cn = new OleDbConnection(cs))
{
cn.Open();
string cmd = #"SELECT wo_cust, lname FROM womast INNER JOIN custmast ON womast.wo_cust = custmast.cust_id WHERE wo_no = #WoNo";
// not sure if it's 'Count' property or 'Count()' method, depending on collection type
for (int i = 0; i < wOSchedulesVM.Count; i++)
{
var sch = wOSchedulesVM[i];
using (OleDbCommand cmdWO = new OleDbCommand(conn, cn))
{
cmd.Parameters.AddWithValue("#WoNo", sch.WoNo)
OleDbDataReader rdr = cmdWO.ExecuteReader();
if (rdr.HasRows)
{
while (rdr.Read())
{
sch.WoCust = (!rdr.IsDbNull(0)) ? rdr.GetString(0).Trim() : string.Empty;
sch.Lname = (!rdr.IsDbNull(1)) ? rdr.GetString(1).Trim() : string.Empty;
}
}
}
}
}
Note: This example includes 3 additional aspects, i.e. parameterized query, checking row existence with HasRows property and checking against DBNull.Value with IsDbNull().
Related issue: What is the best way to modify a list in a 'foreach' loop?

Automapper mapping, how to make a field not mapped

The source class has 2 attributes, the target class 3 attributes, mapping, I think in the target class has 1 attributes unchanged, I use NotMapped, but did not succeed, but NotMapped is not the way I want, what do you do?
class AAA
{
public string Name { set; get; }
public string Id { set; get; }
public string Remark { set; get; }
}
class AAAViewModel
{
public string Name { set; get; }
public string Id { set; get; }
}
protected override MapperConfiguration Configuration => new MapperConfiguration(cfg=>
{
cfg.CreateMap<AAA, AAAViewModel>(MemberList.Destination);
cfg.CreateMap<AAAViewModel, AAA>(MemberList.Source);
});
[Fact]
public void test()
{
AAA a = new AAA() { Id = "1", Name = "name1", Remark = "remark1" };
var avm = Mapper.Map<AAAViewModel>(a);
AAA b = new AAA() { Remark = "remakrb" };
b = Mapper.Map<AAA>(avm);
Assert.Equal(avm.Id, "1");
}
The attribute is called IgnoreMap.

Create a complex type model validation attribute with server and client validation

I'm trying to create an attribute that can validate a complex type both on the server and client side. This attribute will be used for required and non required complex types such as the following Address Class
public partial class AddressViewModel
{
[DisplayName("Address 1")]
[MaxLength(100)]
public virtual string Address1 { get; set; }
[DisplayName("Address 2")]
[MaxLength(100)]
public virtual string Address2 { get; set; }
[MaxLength(100)]
public virtual string City { get; set; }
[MaxLength(50)]
public virtual string State { get; set; }
[MaxLength(10)]
[DisplayName("Postal Code")]
public virtual string PostalCode { get; set; }
[MaxLength(2)]
public virtual string Country { get; set; }
}
The problem is that this model could be required sometimes and optional other times. I know that I could simply create another RequiredAddressViewModel class that has the Required attribute associated with the properties I deem required. I feel like there could be a reusable solution, such as a ValidationAttribute.
I created the following classes and they work server side, but do not work for client side.
public class AddressIfAttribute : ValidationAttribute, IClientValidatable
{
public string Address1 { get; private set; }
public string Address2 { get; private set; }
public string City { get; private set; }
public string State { get; private set; }
public string PostalCode { get; private set; }
public string Country { get; private set; }
public bool IsRequired { get; private set; }
public AddressIfAttribute(bool isRequired) : base("The field {0} is required.")
{
IsRequired = isRequired;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var address = value as AddressViewModel;
Address1 = address.Address1;
Address2 = address.Address2;
City = address.City;
State = address.State;
Country = address.Country;
PostalCode = address.PostalCode;
var results = new List<ValidationResult>();
var context = new ValidationContext(address, null, null);
Validator.TryValidateObject(address, context, results, true);
if (results.Count == 0 && IsRequired)
{
if (string.IsNullOrEmpty(Address2))
return new ValidationResult(string.Format(ErrorMessageString, validationContext.DisplayName));
}
else if (results.Count != 0)
{
var compositeResults = new CompositeValidationResult(string.Format("Validation for {0} failed!", validationContext.DisplayName));
results.ForEach(compositeResults.AddResult);
return compositeResults;
}
return ValidationResult.Success;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
return new[]
{
new ModelClientValidationAddressIfRule(string.Format(ErrorMessageString,metadata.GetDisplayName()), Address1, Address2, City, State, Country, PostalCode,IsRequired)
};
}
}
public class ModelClientValidationAddressIfRule : ModelClientValidationRule
{
public ModelClientValidationAddressIfRule(string errorMessage, object address1, object address2, object city, object state, object country, object postalCode, bool isRequired)
{
ErrorMessage = errorMessage;
ValidationType = "addressif";
ValidationParameters.Add("address1", address1);
ValidationParameters.Add("address2", address2);
ValidationParameters.Add("city", city);
ValidationParameters.Add("state", state);
ValidationParameters.Add("country", country);
ValidationParameters.Add("postalCode", postalCode);
ValidationParameters.Add("isrequired", isRequired.ToString().ToLower());
}
Since the AddressIf attribute is on a complex type the necessary markup isn't added and unobtrusive javascript doesn't validate these fields.
So if I want the rendered HTML to have the proper data-* fields, is my only solution to create another RequiredAddressViewModel? At this point, it might be the easiest.

Entity Framework Insert object with related object

I am a newbie with Entity Framework and I need to insert an object Comment that has a related FK object User into the database.
public Class Comment
{
public int CommentID { get; set; }
public string CommentContent { get; set; }
public virtual User User { get; set; }
public virtual DateTime CommentCreationTime { get; set; }
}
public class User
{
public int UserID { get; set; }
public string UserName { get; set; }
public string UserPassword { get; set; }
public string UserImageUrl{get; set;}
public DateTime UserCreationDate { get; set; }
public virtual List<Comment> Comments { get; set; }
}
public void AddComment()
{
User user = new User() { UserID = 1 };
Comment comment = new Comment() { CommentContent = "This is a comment", CommentCreationTime = DateTime.Now, User = user };
var ctx = new WallContext();
comments = new CommentsRepository(ctx);
comments.AddComment(comment);
ctx.SaveChanges();
}
Ideally, with T-SQL, if I know the PRIMARY KEY of my User object, I could just insert my Comment object and specify the PK of my 'User' in the insert statement.
I have tried to do the same with Entity Framework and it doesn't seem to work. It would be overkill to have to first fetch the User object from the database just to insert a new 'Comment'.
Please, how can I achieve this ?
You need to attach the user object to the context so that the context knows its an existing entity
public void AddComment()
{
var ctx = new WallContext();
User user = new User() { UserID = 1 };
ctx.Users.Attach(user);
Comment comment = new Comment() { CommentContent = "This is a comment", CommentCreationTime = DateTime.Now, User = user };
comments = new CommentsRepository(ctx);
comments.AddComment(comment);
ctx.SaveChanges();
}

SubSonic Simple Repository One-To-Many

I made a class like:
public class Video
{
public Guid VideoID { get; set; }
public VideoCategory VideoCategory { get; set; }
public int SortIndex { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public string Author { get; set; }
public string Filename { get; set; }
public new void Add()
{
this.VideoID = Guid.NewGuid();
DB.Repository.Add(this);
}
}
And another like
public class VideoCategory
{
public Guid VideoCategoryID { get; set; }
public string Title { get; set; }
public new void Add()
{
this.VideoCategoryID = Guid.NewGuid();
DB.Repository.Add(this);
}
}
I then have code like:
VideoCategory VideoCategory = new VideoCategory();
VideoCategory.Title = "TestTitle";
VideoCategory.Add();
Video Video = new Video();
Video.VideoCategory = VideoCategory;
Video.SortIndex = 1;
Video.Title = "TestTitle";
Video.Body = "TestBody";
Video.Author = "TestAuthor";
Video.Filename = "TestFile.flv";
Video.Add();
It doesn't save the VideoCategory into my database, so obviously i'm missing something. What else is needed to done to save a one-to-many relationship?
You could probably just do the following, you'll probably want to tidy it up but it will ensure your foreign key value gets populated:
public class Video
{
protected VideoCategory videoCategory;
public Guid ID { get; set; }
public VideoCategory VideoCategory
{
get { return videoCategory; }
set
{
videoCategory = value;
VideoCategoryId = value.ID;
}
}
public Guid VideoCategoryId { get; set; }
public int SortIndex { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public string Author { get; set; }
public string Filename { get; set; }
}
public class VideoCategory
{
public Guid ID { get; set; }
public string Title { get; set; }
}
SimpleRepository repo = new SimpleRepository(SimpleRepositoryOptions.RunMigrations);
VideoCategory videoCategory = new VideoCategory();
videoCategory.ID = Guid.NewGuid();
videoCategory.Title = "TestTitle";
repo.Add<VideoCategory>(videoCategory);
Video video = new Video();
video.ID = Guid.NewGuid();
video.VideoCategory = videoCategory;
video.SortIndex = 1;
video.Title = "TestTitle";
video.Body = "TestBody";
video.Author = "TestAuthor";
video.Filename = "TestFile.flv";
repo.Add<Video>(video);
You're not missing anything. Simplerepository doesn't support one to many out of the box.
Heres a useful link that shows how to mangage foreign keys yourself in SimpleRepository -
subsonic-3-simplerepository
Have not tried it myself, but looks like it would actually work.
Fluent Nhibernate will do this foriegn key management for you automatically, but it's a LOT more complex.
PS If this was helpful, please vote it up.

Resources