Monday 18 May 2015

Using When, All, Then and Reject functions of $q Service

We will see how to use when, all, then and reject functions of the AngularJS $q service. To learn the basic usage of $q, please see my previous post.

$q.when
$q.when() can be used to wrap an object or function if we are not sure whether it returns a promise or not. If we wrap a value object or a value returned function, the value will be passed as a result argument to the next function. When we wrap a function, the when() method will ensure that the function is executed first before going to the next one.

Below are some code examples:
$q.when('aaa').then(function(result) {
    alert(result);
})

var vm = this;
vm.chars = '';

$q.when(_test()).then(function(){
 vm.chars = vm.chars + 'END'
})

_test = function() {
 for (i = 0; i <= 10000; i++) {
   vm.chars = vm.chars + '.'
 }
}


$q.all
$q.all() is used to combine promise returned functions and only continue to progress further after all of the functions complete successfully. If one of the functions fails, immediately as soon as $q.all() gets a rejected promise from one of the functions, it will end the execution and pass forward to an error callback if there is any.
vm.numbers = '';    
_promiseFunction = function(x) {
 var deferred = $q.defer();

 if (x > 0) {
   deferred.resolve(x * 100);
 } else {
   deferred.reject(x + " is smaller than 0")
 }

 return deferred.promise;
}
 
var first = _promiseFunction(1);
var second = _promiseFunction(5);
var third = _promiseFunction(10);
var four = _promiseFunction(-1);
var five = _promiseFunction(-10)

$q.all([first, second, third /*, four, five*/]).
then(function(results){
  console.log(results.length);
  for(i=0; i < results.length; i++) {
    vm.numbers = vm.numbers + ' ' + results[i];
  }
 },
 function(errors){
  // if there is any error in the sequence, the success callback will not be called
  console.log(errors);
 })


$q.then
$q.then() is useful for executing asynchronous functions (or blocks of codes) sequentially in a chain. If the function inside a then() does not return a promise, it will be wrapped as a resolved promise. Otherwise the resolved or rejected promise will be passed forward.

_promiseFunction(5).then(
 function() { alert('aaa')}
).then(
 function() { alert('bbb');}
).then(
 function() {alert('ccc');}
);

_promiseFunction(5).then(
 function() { return $q.reject('failed')}
).then(
 function(){ alert('result success')},
 function(){ alert('result fail')}
)

Note also that if we return a non-promise value in the error callback inside then(), this will be treated as a resolved promise. So we need to be careful when handling error if our intention is to pass the error forward to the next function.
$q.reject().then(
 // success
 function() {},
 // error
 function(error) {
   return 'i got the error'
 }
).then(
 //success
 function() {
   alert('success');
 },
 // error
 function() {
   alert('error')
 }
)

$q.reject
Last thing, we have $q.reject() that is useful as a quick way to create then send a rejected promise (with a value optionally) to the next function in a chain. For example, in a chain of multiple then(). We can see this in the last two examples.

See the examples in Plunker.

Friday 15 May 2015

Setting Up One to Many Relationship with Fluent API in Code First

Let's say that we would like to have a one to many relationship between two tables, e.g. User and Article. A User can have many Articles. Below are two ways of how we could specify the models and relationship configuration with Fluent API.

1. Without Having Foreign Key Property in Model
public class Article 
{
 public int Id { get; set; }

 [StringLength(150)]
 [Required]
 public string Title { get; set; }

 [Required]
 public string Description { get; set; }

 [StringLength(500)]
 [Required]
 public string Url { get; set; }

 #region navigation properties
 public virtual User Submitter { get; set; }
 #endregion
}


public class User 
{
 public int Id { get; set; }
 
 [StringLength(100)]
 [Required]
 public string Firstname { get; set; }
 
 [StringLength(100)]
 [Required]
 public string Lastname { get; set; }

 #region navigational property
 public virtual ICollection<Article> Articles { get; set; }
 #endregion
}


protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
 #region Article table
 modelBuilder.Entity<Article>().HasKey(t => t.Id);
 // specify the relationship between the two tables
 modelBuilder.Entity<Article>().HasRequired(t => t.Submitter).WithMany(t => t.Articles);
 #endregion

 #region User table
 modelBuilder.Entity<User>().HasKey(t => t.Id);
 #endregion
}
Before we go further, I would like to say that I prefer to use Data Annotation attributes in a model for validation purpose only for its properties. The database related configurations are done inside OnModelCreating() method.

On the codes above, we do not specify any foreign key property such as 'SubmitterId'. We do this purely in 'code first perspective' only which focuses on models and 'code' relationships between them, not their relational database relationships. So we do not worry on specifying any foreign key property here, we only specify the navigational property.

Please note as well that we do not put a [Required] attribute on the navigation property even though we always want this model to have a navigational property object (i.e. an article must have a submitter). This would create an issue for us later when we want to update an article object only without worrying about submitter. It is better to specify this rule when specifying the relationship in Fluent API.

To let Code First know the relationship we want, we put this on OnModelCreating() method:
modelBuilder.Entity<Article>().HasRequired(t => t.Submitter).WithMany(t => t.Articles);
The validation rule that the navigational property (i.e. submitter) is required is set here.

Code First will generate tables like below:



2. With Foreign Key Property in Model
If we prefer to specify foreign key property in our model, then we can do this way:
// add foreign key property to the model (Article)
public int SubmitterId { get; set; }
The advantage of doing it this way is that we can name it with any name we like.

Then on OnModelCreating() method, we write:
modelBuilder.Entity<Article>().HasRequired(t => t.Submitter).WithMany(t => t.Articles).HasForeignKey(t => t.SubmitterId);

Below are the tables and columns that will be generated:



For setting other configurations using fluent API, please see this post.

Monday 11 May 2015

MergeOptions in Entity Framework

Understanding MergeOption when using Entity Framework is important, especially when you do multiple operations of the same object within a context.

If we have codes like these ones and assume the MergeOption is applied to all operations:
// first query
var listOne = Context.Students.OrderBy(s => s.Id).Take(2).ToList();
var studentA = listOne.First();

// first update
studentA.FirstName = "Updated";


// second query
var listTwo = Context.Students.OrderBy(s => s.Id).Take(5).ToList();
var studentB = listTwo.First();

// second update
studentB.FirstName = "UpdatedB";

The four options are:
- NoTracking
Objects are maintained in a Detached state and are not tracked in the ObjectStateManager. As the object is not tracked, object cannot be updated. On the second query, EF will get fresh records from the data source, including the ones that have been retrieved by query one then populate listTwo.

- AppendOnly (default)
Objects that do not exist in the context are attached to the context. Object that is already tracked in the context, will not be overwritten when EF retrieves records again from data source. On the second query, only three other student objects are retrieved from data source.
If there's change in values in the data source between first and second queries, all tracked objects in the context will not have the latest values from data source after retrieving on the second query.

- PreserveChanges
Similar like AppendOnly, but will replace unmodified objects (objects with EntityState Unchanged) from data source. On the second query, the other student object from first query and three new ones will be retrieved from data source.
If there's change in values in the data source between first and second queries, modified objects in the context will not have the latest values from data source after retrieving on the second query. The unmodified objects will be refreshed and have latest values from data source.

- OverwriteChanges
Objects will be replaced with fresh records from data source. If a change is made and not committed to data source yet, when retrieving from data source again the change will be lost and replaced with the retrieved value from data source. In our example, the first update is lost when second query is made. All objects will then reset to Unchanged state.
If there's change in values in the data source between first and second queries, all objects in the context will have the latest values from data source after retrieving on the second query.


References:
https://docs.microsoft.com/en-us/dotnet/api/system.data.objects.mergeoption?view=netframework-4.8
https://community.dynamics.com/crm/b/develop1/posts/do-you-understand-mergeoptions