Permission Contacts in Xamarin Forms iOS - xamarin

I met an error display when I tried to access user contact to fetch all contacts: The splash screen hide the permission dialog.
Did anyone meet this error before?
Interface:
public interface IUserContactsService
{
List<PhoneContactInfo> GetAllPhoneContacts(IEnumerable<int> filterIds = null);
}
UserContactService.cs:
[assembly: Dependency(typeof(UserContactService))]
namespace Test.iOS
{
public class PhoneContact
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string PhoneNumber { get; set; }
public string Name { get => $"{FirstName} {LastName}"; }
}
public class UserContactService : IUserContactsService
{
string phoneNumber(string number)
{
string callNumber = number;
int i = 0;
while (i < callNumber.Length)
{
if (callNumber[i] == ' ' || callNumber[i] == 160 || callNumber[i] == '-')
callNumber = callNumber.Remove(i, 1);
else
i++;
}
return callNumber;
}
public List<PhoneContactInfo> GetAllPhoneContacts(IEnumerable<int> filterIds = null)
{var keysTOFetch = new[] { CNContactKey.GivenName, CNContactKey.FamilyName, CNContactKey.EmailAddresses };
NSError error;
CNContact[] contactList;
var ContainerId = new CNContactStore().DefaultContainerIdentifier;
using (var predicate = CNContact.GetPredicateForContactsInContainer(ContainerId))
using (var store = new CNContactStore())
{
contactList = store.GetUnifiedContacts(predicate, keysTOFetch, out error);
}
var contacts = new List<PhoneContactInfo>();
foreach (var item in contactList)
{
if (null != item && null != item.EmailAddresses)
{
contacts.Add(new PhoneContactInfo
{
contactName = item.GivenName,
contactNumber = item.PhoneNumbers.ToString()
});
}
}
return contacts;
}
}

Here is my solution:
public List<PhoneContactInfo> GetAllPhoneContacts (IEnumerable<int> filterIds = null)
{
// if the app was not authorized then we need to ask permission
if (ABAddressBook.GetAuthorizationStatus() == ABAuthorizationStatus.Authorized)
{
GetContacts();
}
else Console.WriteLine("Error");
}

Related

how to show a alert if table is empty?

I want to show a alert if table is empty, problem is that i have to click twice before he is hitting
the else statement to show my alert.
I use a overlay to show the devices.
I tried OnafterrenderAsync, OnInitializedAsync, OnParameterSetAsync
If the api call gets devices than there is no problem, the table is loading but if there is no data in the table he doesn't go to the else statement to show my mudalert
<PageTitle>#AccountResource.DevicesLinkLabel</PageTitle>
#if (isLoading)
{
}
else
{
#if (!isShowing)
{
<MudTable T="DeviceModel" ServerData="#(new Func<TableState, Task<TableData<DeviceModel>>>(LoadData))" Hover="true" Breakpoint="Breakpoint.Sm" Dense="true" #ref="table">
<HeaderContent>
<MudTh>#AccountResource.DevicesLinkLabel</MudTh>
<MudTh>#SharedResource.Type</MudTh>
<MudTh>#SharedResource.Version</MudTh>
<MudTh>#SharedResource.VersionAppNumber</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="DeviceName">#context.DisplayName</MudTd>
<MudTd DataLabel="DeviceType">#context.Type</MudTd>
<MudTd DataLabel="DeviceVersion">#context.Version</MudTd>
<MudTd DataLabel="DeviceVersionAppNumber">#context.VersionAppNumber</MudTd>
</RowTemplate>
<PagerContent>
<MudTablePager />
</PagerContent>
</MudTable>
}
else
{
<MudAlert Severity="MudBlazor.Severity.Warning">#SharedResource.NothingToShow</MudAlert>
}
}
#code {
[Parameter]
public long UserId { get; set; }
[Parameter]
public long OrganisationId { get; set; }
[Parameter]
public EventCallback<ModelBase> ShowResponseInToast { get; set; }
private MudTable<DeviceModel>? table;
private bool isLoading = true;
private bool isShowing;
protected override async Task OnParametersSetAsync()
{
try
{
if (table != null)
{
//table.CurrentPage = 0;s
await table.ReloadServerData();
}
}
finally
{
isLoading = false;
}
}
private async Task<TableData<DeviceModel>> LoadData(TableState state)
{
var request = new GetDeviceRequest
{
OrganisationId = OrganisationId,
UserId = UserId,
Page = state.Page,
PageSize = state.PageSize,
};
var response = await DeviceManagerClient.GetDeviceResponseAsync(request);
if (table?.Items?.Any() == true)
{
isShowing = false;
return new TableData<DeviceModel>
{
Items = response.Results,
TotalItems = response.TotalCount
};
}
else
{
isShowing = true;
return new TableData<DeviceModel>
{
Items = response.Results,
};
}
}
}

how to implement Android In App BillingClient in Xamarin.Android Asynchronously

I am trying to implement below java code in c# referring to Android documentation
List<String> skuList = new ArrayList<> ();
skuList.add("premium_upgrade");
skuList.add("gas");
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(SkuType.INAPP);
billingClient.querySkuDetailsAsync(params.build(),
new SkuDetailsResponseListener() {
#Override
public void onSkuDetailsResponse(BillingResult billingResult,
List<SkuDetails> skuDetailsList) {
// Process the result.
}
});
I have here 2 questions. I thought that i would run this code on a separate thread than UI thread like below to keep my ui responsive while network connection is done. is that the correct approach? QuerySkuDetailsAsync is called async but doesnt implement as async. how should this be working and how to handle in c# because it will fire and forget but Listener to handle the response.
public async Task<List<InAppBillingProduct>> GetProductsAsync(List<string> ProductIds)
{
var getSkuDetailsTask = Task.Factory.StartNew(() =>
{
var prms = SkuDetailsParams.NewBuilder();
var type = BillingClient.SkuType.Inapp;
prms.SetSkusList(ProductIds).SetType(type);
BillingClient.QuerySkuDetailsAsync(prms.Build(), new SkuDetailsResponseListener());
return InAppBillingProducts;
});
return await getSkuDetailsTask;
}
2nd question regarding how to handle with the listener as below. How do I return value from the listener. I need return list of InAppBillingProduct object.
public class SkuDetailsResponseListener : Java.Lang.Object, ISkuDetailsResponseListener
{
public void OnSkuDetailsResponse(BillingResult billingResult, IList<SkuDetails> skus)
{
if (billingResult.ResponseCode == BillingResponseCode.Ok)
{
// get list of Products here and return
}
}
}
FYI. This is how I did it. This is not a complete code but this will give you and idea.
Listener - PCL
============
private async Task EventClicked()
{
var skuList = new List<string>();
skuList.Add("[nameofsubscriptionfoundinyourgoogleplay]");
if (await _billingClientLifecycle.Initialize(skuList, DisconnectedConnection))
{
var firstProduct = _billingClientLifecycle?.ProductsInStore?.FirstOrDefault();
if (firstProduct != null)
{
//purchase here
}
}
}
private void DisconnectedConnection()
{
//Todo.alfon. handle disconnection here...
}
Interface - PCL
===========
public interface IInAppBillingMigratedNew
{
List<InAppBillingPurchase> PurchasedProducts { get; set; }
List<InAppBillingProduct> ProductsInStore { get; set; }
Task<bool> Initialize(List<String> skuList, Action onDisconnected = null);
}
Dependency - Platform Droid
===============
[assembly: XF.Dependency(typeof(InAppBillingMigratedNew))]
public class InAppBillingMigratedNew : Java.Lang.Object, IBillingClientStateListener
, ISkuDetailsResponseListener, IInAppBillingMigratedNew
{
private Activity Context => CrossCurrentActivity.Current.Activity
?? throw new NullReferenceException("Current Context/Activity is null");
private BillingClient _billingClient;
private List<string> _skuList = new List<string>();
private TaskCompletionSource<bool> _tcsInitialized;
private Action _disconnectedAction;
private Dictionary<string, SkuDetails> _skusWithSkuDetails = new Dictionary<string, SkuDetails>();
public List<InAppBillingPurchase> PurchasedProducts { get; set; }
public List<InAppBillingProduct> ProductsInStore { get; set; }
public IntPtr Handle => throw new NotImplementedException();
public Task<bool> Initialize(List<string> skuList, Action disconnectedAction = null)
{
_disconnectedAction = disconnectedAction;
_tcsInitialized = new TaskCompletionSource<bool>();
var taskInit = _tcsInitialized.Task;
_skuList = skuList;
_billingClient = BillingClient.NewBuilder(Context)
.SetListener(this)
.EnablePendingPurchases()
.Build();
if (!_billingClient.IsReady)
{
_billingClient.StartConnection(this);
}
return taskInit;
}
#region IBillingClientStateListener
public void OnBillingServiceDisconnected()
{
Console.WriteLine($"Connection disconnected.");
_tcsInitialized?.TrySetResult(false);
_disconnectedAction?.Invoke();
}
public void OnBillingSetupFinished(BillingResult billingResult)
{
var responseCode = billingResult.ResponseCode;
var debugMessage = billingResult.DebugMessage;
if (responseCode == BillingResponseCode.Ok)
{
QuerySkuDetails();
QueryPurchases();
_tcsInitialized?.TrySetResult(true);
}
else
{
Console.WriteLine($"Failed connection {debugMessage}");
_tcsInitialized?.TrySetResult(false);
}
}
#endregion
#region ISkuDetailsResponseListener
public void OnSkuDetailsResponse(BillingResult billingResult, IList<SkuDetails> skuDetailsList)
{
if (billingResult == null)
{
Console.WriteLine("onSkuDetailsResponse: null BillingResult");
return;
}
var responseCode = billingResult.ResponseCode;
var debugMessage = billingResult.DebugMessage;
switch (responseCode)
{
case BillingResponseCode.Ok:
if (skuDetailsList == null)
{
_skusWithSkuDetails.Clear();
}
else
{
if (skuDetailsList.Count > 0)
{
ProductsInStore = new List<InAppBillingProduct>();
}
foreach (var skuDetails in skuDetailsList)
{
_skusWithSkuDetails.Add(skuDetails.Sku, skuDetails);
//ToDo.alfon. make use mapper here
ProductsInStore.Add(new InAppBillingProduct
{
Name = skuDetails.Title,
Description = skuDetails.Description,
ProductId = skuDetails.Sku,
CurrencyCode = skuDetails.PriceCurrencyCode,
LocalizedIntroductoryPrice = skuDetails.IntroductoryPrice,
LocalizedPrice = skuDetails.Price,
MicrosIntroductoryPrice = skuDetails.IntroductoryPriceAmountMicros,
MicrosPrice = skuDetails.PriceAmountMicros
});
}
}
break;
case BillingResponseCode.ServiceDisconnected:
case BillingResponseCode.ServiceUnavailable:
case BillingResponseCode.BillingUnavailable:
case BillingResponseCode.ItemUnavailable:
case BillingResponseCode.DeveloperError:
case BillingResponseCode.Error:
Console.WriteLine("onSkuDetailsResponse: " + responseCode + " " + debugMessage);
break;
case BillingResponseCode.UserCancelled:
Console.WriteLine("onSkuDetailsResponse: " + responseCode + " " + debugMessage);
break;
// These response codes are not expected.
case BillingResponseCode.FeatureNotSupported:
case BillingResponseCode.ItemAlreadyOwned:
case BillingResponseCode.ItemNotOwned:
default:
Console.WriteLine("onSkuDetailsResponse: " + responseCode + " " + debugMessage);
break;
}
}
#endregion
#region Helper Methods Private
private void ProcessPurchases(List<Purchase> purchasesList)
{
if (purchasesList == null)
{
Console.WriteLine("No purchases done.");
return;
}
if (IsUnchangedPurchaseList(purchasesList))
{
Console.WriteLine("Purchases has not changed.");
return;
}
_purchases.AddRange(purchasesList);
PurchasedProducts = _purchases.Select(sku => new InAppBillingPurchase
{
PurchaseToken = sku.PurchaseToken
})?.ToList();
if (purchasesList != null)
{
LogAcknowledgementStatus(purchasesList);
}
}
private bool IsUnchangedPurchaseList(List<Purchase> purchasesList)
{
// TODO: Optimize to avoid updates with identical data.
return false;
}
private void LogAcknowledgementStatus(List<Purchase> purchasesList)
{
int ack_yes = 0;
int ack_no = 0;
foreach (var purchase in purchasesList)
{
if (purchase.IsAcknowledged)
{
ack_yes++;
}
else
{
ack_no++;
}
}
//Log.d(TAG, "logAcknowledgementStatus: acknowledged=" + ack_yes +
// " unacknowledged=" + ack_no);
}
private void QuerySkuDetails()
{
var parameters = SkuDetailsParams
.NewBuilder()
.SetType(BillingClient.SkuType.Subs)
.SetSkusList(_skuList)
.Build();
_billingClient.QuerySkuDetailsAsync(parameters, this);
}
private void QueryPurchases()
{
if (!_billingClient.IsReady)
{
Console.WriteLine("queryPurchases: BillingClient is not ready");
}
var result = _billingClient.QueryPurchases(BillingClient.SkuType.Subs);
ProcessPurchases(result?.PurchasesList?.ToList());
}
#endregion
}

PetaPoco returns empty object

Inside my applocation, the petapoco poco returns an empty object (all values are null). Using the UI-O-Matic Nuget package inside my Umbraco 7.5.12.
The query i'm currently running:
var dbContext = ApplicationContext.Current.DatabaseContext;
var objects = dbContext.Database.Fetch<ObjectDB>("select Id, Name, CreatedOn, PlaceId, InActive, CityMapping, CountryIsoMapping, Globalsearch from ObjectsDB");
return objects.Where(n => n.PlaceId == PlaceId).FirstOrDefault();
TableDB is my PetaPoco model with the fields like:
[UIOMatic("ObjectsDB", "Object", "Object", FolderIcon = "icon-globe-inverted-europe-africa", ItemIcon = "icon-pin-location", RenderType = UIOMaticRenderType.List)]
[TableName("ObjectsDB")]
[PrimaryKey("Id", autoIncrement = false)]
[ExplicitColumns]
public class ObjectDB
{
[PrimaryKeyColumn(AutoIncrement = true)]
public int Id { get; set; }
[UIOMaticListViewFilter]
[UIOMaticListViewField(Name = "Name")]
[UIOMaticField(Name = "Name", Description = "Name")]
public string Name { get; set; }
}
When debuging:
`Debug result: con.Single<ObjectsDB>("select Name, Id from ObjectsDB where Id = 4")
This retruns the object:
{Umbraco.Extensions.Models.Custom.ObjectsModel.ObjectsDB} _createdOn: {1/1/0001 12:00:00 AM}
CityMapping: null
CountryIsoMapping: null
CreatedOn: {5/19/2017 4:22:16 PM}
Globalsearch: false
Id: 0
InActive: false
InCache: false
Name: null
Object: null
PlaceId: null `
Inserting data is working with the same dbContext, that's working.
What am I missing here?
I have used Petapoco in various Umbraco project and my approach is a bit different than your approach. I am sharing it here, hope it helps you.
This is the nuget package that I have used:(http://nuget.org/List/Packages/PetaPoco)
Please see my sample code below or in my blog:
[PetaPoco.TableName("fsCarts")]
[PetaPoco.PrimaryKey("RecordID")]
public class Cart
{
[Key]
public int RecordId { get; set; }
public string CartId { get; set; }
public Guid ProductId { get; set; }
public int Count { get; set; }
public DateTime DateCreated { get; set; }
}
UmbracoDatabase con = ApplicationContext.Current.DatabaseContext.Database;
public void AddToCart(Product product)
{
try
{
var cartItem = con.FirstOrDefault<Cart>("SELECT * FROM fsCarts WHERE CartID=#0 AND ProductID=#1", ShoppingCardId, product.ProductId);
if (cartItem == null)
{
cartItem = new Cart
{
ProductId = product.ProductId,
CartId = ShoppingCardId,
Count = 1,
DateCreated = DateTime.Now
};
con.Insert("fsCarts", "RecordID", cartItem);
}
else
{
cartItem.Count++;
con.Update("fsCarts", "RecordID", cartItem);
}
}
catch (Exception ex)
{
Elmah.ErrorLog.GetDefault(null).Log(new Elmah.Error(new Exception("Shopping Cart AddToCart: " + ex.ToString())));
}
}
////////////////////
public int RemoveFromCart(int id)
{
int itemCount = 0;
try
{
var cartItem = con.FirstOrDefault<Cart>("SELECT * FROM fsCarts WHERE CartID=#0 AND RecordId=#1", ShoppingCardId, id);
if (cartItem != null)
{
if (cartItem.Count > 1)
{
cartItem.Count--;
itemCount = cartItem.Count;
con.Update("fsCarts", "RecordID", cartItem);
}
else
{
con.Delete("fsCarts", "RecordID", cartItem);
}
}
}
catch (Exception ex)
{
Elmah.ErrorLog.GetDefault(null).Log(new Elmah.Error(new Exception("Shopping Cart RemoveFromCart: " + ex.ToString())));
}
return itemCount;
}
////////////////////
public List<Cart> GetCartItems()
{
List<Cart> cartItemList = new List<Cart>();
try
{
cartItemList = con.Query<Cart>("SELECT * FROM fsCarts WHERE CartID=#0", ShoppingCardId).ToList();
}
catch (Exception ex)
{
Elmah.ErrorLog.GetDefault(null).Log(new Elmah.Error(new Exception("Shopping Cart GetCartItems: " + ex.ToString())));
}
return cartItemList;
}
////////////////////
public decimal GetTotal()
{
decimal? total = null;
try
{
total = con.ExecuteScalar<decimal>("SELECT SUM(ISNULL(p.Price,0)*c.Count) FROM fsCarts c INNER JOIN fsProducts p ON c.ProductID=p.ProductID WHERE c.CartID=#0", ShoppingCardId);
}
catch (Exception ex)
{
Elmah.ErrorLog.GetDefault(null).Log(new Elmah.Error(new Exception("Shopping Cart GetTotal: " + ex.ToString())));
}
return total ?? decimal.Zero;
}
Removing the attribute [ExplicitColumns] above my class fixed the problem. No everything works as expected. Also the other decorations are working. So #Nurhak Kaya was partially right. After removing that attribute deleting the table and rebuild / generating the table.

EF 4.1, database first and Many-to-Many relationships - How to get all sub-objects?

Let's say I have the following tables in a database forming a Many-to-Many Relationship. And in an ASP.Net MVC project using EF 4.1, I have corresponding POCO entities and a Repository layer to access the database.
People: PersonId PK, Firsname, Lastname
FavoriteRestaurants: ID PK, PersonId, RestaurantId
Restaurants: ResaurantId PK, Name
If I have a PersonId, what is the best way to list all this person's favorite restaurant names?
Or how would I do to initialise this Enumerable based on the person's Id using a repository layer?
IEnumerable MyFavoriteRestaurants = ???
I know I could use foreach to loop on the Person.FavoriteRestaurants collections an retrieve each FavoriteRestaurant.Restaurant one by one, but I was wondering if there were a more elegant way to do this in one line of code.
UPDATE
Here is an example of a Person POCO entity class in my project. This code has been generated by a Microsoft template downloaded from here:
http://visualstudiogallery.msdn.microsoft.com/23df0450-5677-4926-96cc-173d02752313/
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
namespace UpDir.Domain
{
public partial class Person : EntityBase
{
#region Primitive Properties
public virtual int PersonId
{
get;
set;
}
public virtual string Firstname
{
get;
set;
}
public virtual string Middlename
{
get;
set;
}
public virtual string Lastname
{
get;
set;
}
public virtual string Nickname
{
get;
set;
}
public virtual string EncryptedEmail
{
get;
set;
}
public virtual string Photo
{
get;
set;
}
public virtual short StatusId
{
get { return _statusId; }
set
{
if (_statusId != value)
{
if (Status != null && Status.StatusId != value)
{
Status = null;
}
_statusId = value;
}
}
}
private short _statusId;
#endregion
#region Navigation Properties
public virtual ICollection<Member> Members
{
get
{
if (_members == null)
{
var newCollection = new FixupCollection<Member>();
newCollection.CollectionChanged += FixupMembers;
_members = newCollection;
}
return _members;
}
set
{
if (!ReferenceEquals(_members, value))
{
var previousValue = _members as FixupCollection<Member>;
if (previousValue != null)
{
previousValue.CollectionChanged -= FixupMembers;
}
_members = value;
var newValue = value as FixupCollection<Member>;
if (newValue != null)
{
newValue.CollectionChanged += FixupMembers;
}
}
}
}
private ICollection<Member> _members;
public virtual ICollection<Message> Messages
{
get
{
if (_messages == null)
{
var newCollection = new FixupCollection<Message>();
newCollection.CollectionChanged += FixupMessages;
_messages = newCollection;
}
return _messages;
}
set
{
if (!ReferenceEquals(_messages, value))
{
var previousValue = _messages as FixupCollection<Message>;
if (previousValue != null)
{
previousValue.CollectionChanged -= FixupMessages;
}
_messages = value;
var newValue = value as FixupCollection<Message>;
if (newValue != null)
{
newValue.CollectionChanged += FixupMessages;
}
}
}
}
private ICollection<Message> _messages;
public virtual ICollection<Notification> Notifications
{
get
{
if (_notifications == null)
{
var newCollection = new FixupCollection<Notification>();
newCollection.CollectionChanged += FixupNotifications;
_notifications = newCollection;
}
return _notifications;
}
set
{
if (!ReferenceEquals(_notifications, value))
{
var previousValue = _notifications as FixupCollection<Notification>;
if (previousValue != null)
{
previousValue.CollectionChanged -= FixupNotifications;
}
_notifications = value;
var newValue = value as FixupCollection<Notification>;
if (newValue != null)
{
newValue.CollectionChanged += FixupNotifications;
}
}
}
}
private ICollection<Notification> _notifications;
public virtual Status Status
{
get { return _status; }
set
{
if (!ReferenceEquals(_status, value))
{
var previousValue = _status;
_status = value;
FixupStatus(previousValue);
}
}
}
private Status _status;
public virtual ICollection<UpDirEmail> FromEmails
{
get
{
if (_fromEmails == null)
{
var newCollection = new FixupCollection<UpDirEmail>();
newCollection.CollectionChanged += FixupFromEmails;
_fromEmails = newCollection;
}
return _fromEmails;
}
set
{
if (!ReferenceEquals(_fromEmails, value))
{
var previousValue = _fromEmails as FixupCollection<UpDirEmail>;
if (previousValue != null)
{
previousValue.CollectionChanged -= FixupFromEmails;
}
_fromEmails = value;
var newValue = value as FixupCollection<UpDirEmail>;
if (newValue != null)
{
newValue.CollectionChanged += FixupFromEmails;
}
}
}
}
private ICollection<UpDirEmail> _fromEmails;
public virtual ICollection<UpDirEmail> ToEmails
{
get
{
if (_toEmails == null)
{
var newCollection = new FixupCollection<UpDirEmail>();
newCollection.CollectionChanged += FixupToEmails;
_toEmails = newCollection;
}
return _toEmails;
}
set
{
if (!ReferenceEquals(_toEmails, value))
{
var previousValue = _toEmails as FixupCollection<UpDirEmail>;
if (previousValue != null)
{
previousValue.CollectionChanged -= FixupToEmails;
}
_toEmails = value;
var newValue = value as FixupCollection<UpDirEmail>;
if (newValue != null)
{
newValue.CollectionChanged += FixupToEmails;
}
}
}
}
private ICollection<UpDirEmail> _toEmails;
public virtual ICollection<UpDirEvent> UpDirEvents
{
get
{
if (_upDirEvents == null)
{
var newCollection = new FixupCollection<UpDirEvent>();
newCollection.CollectionChanged += FixupUpDirEvents;
_upDirEvents = newCollection;
}
return _upDirEvents;
}
set
{
if (!ReferenceEquals(_upDirEvents, value))
{
var previousValue = _upDirEvents as FixupCollection<UpDirEvent>;
if (previousValue != null)
{
previousValue.CollectionChanged -= FixupUpDirEvents;
}
_upDirEvents = value;
var newValue = value as FixupCollection<UpDirEvent>;
if (newValue != null)
{
newValue.CollectionChanged += FixupUpDirEvents;
}
}
}
}
private ICollection<UpDirEvent> _upDirEvents;
#endregion
#region Association Fixup
private void FixupStatus(Status previousValue)
{
if (previousValue != null && previousValue.People.Contains(this))
{
previousValue.People.Remove(this);
}
if (Status != null)
{
if (!Status.People.Contains(this))
{
Status.People.Add(this);
}
if (StatusId != Status.StatusId)
{
StatusId = Status.StatusId;
}
}
}
private void FixupMembers(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (Member item in e.NewItems)
{
item.Person = this;
}
}
if (e.OldItems != null)
{
foreach (Member item in e.OldItems)
{
if (ReferenceEquals(item.Person, this))
{
item.Person = null;
}
}
}
}
private void FixupMessages(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (Message item in e.NewItems)
{
item.Person = this;
}
}
if (e.OldItems != null)
{
foreach (Message item in e.OldItems)
{
if (ReferenceEquals(item.Person, this))
{
item.Person = null;
}
}
}
}
private void FixupNotifications(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (Notification item in e.NewItems)
{
item.Person = this;
}
}
if (e.OldItems != null)
{
foreach (Notification item in e.OldItems)
{
if (ReferenceEquals(item.Person, this))
{
item.Person = null;
}
}
}
}
private void FixupFromEmails(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (UpDirEmail item in e.NewItems)
{
item.FromPerson = this;
}
}
if (e.OldItems != null)
{
foreach (UpDirEmail item in e.OldItems)
{
if (ReferenceEquals(item.FromPerson, this))
{
item.FromPerson = null;
}
}
}
}
private void FixupToEmails(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (UpDirEmail item in e.NewItems)
{
item.ToPerson = this;
}
}
if (e.OldItems != null)
{
foreach (UpDirEmail item in e.OldItems)
{
if (ReferenceEquals(item.ToPerson, this))
{
item.ToPerson = null;
}
}
}
}
private void FixupUpDirEvents(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (UpDirEvent item in e.NewItems)
{
item.Person = this;
}
}
if (e.OldItems != null)
{
foreach (UpDirEvent item in e.OldItems)
{
if (ReferenceEquals(item.Person, this))
{
item.Person = null;
}
}
}
}
#endregion
}
}
You don't need to think too much about that, EF will do it for you if you have defined your entity classes correct way like this,
Public class Person{
public int PersonId {get;set;}
public string Firsname{get;set;}
....
public virtual IList<Resturent> Resturents {get;set;}
}
Public class Restaurant{
public int ResaurantId {get;set;}
public string Name{get;set;}
....
public virtual IList<Resturent> People{get;set;}
}
Then you can simply access person.Restaurants to get all restaurants.
I finally figured it out. This is how I am doing it:
IEnumerable<Restaurants> MyFavoriteRestaurants = person.FavoriteRestaurants.Select(m => m.Restaurants);

EmitMapper and List

It's the first time that I use EmitMapper.
I have a list of object ex: Customer and I would like to map this list in a ienumerable of CustomerDTO how can I do that?
Tnx
It's straightforward if you have a list and want to convert it to list of DTOs:
var mapper = ObjectMapperManager.DefaultInstance.GetMapper<Customer, CustomerDTO>();
IEnumerable<CustomerDTO> dtos = listOfCustomer.Select(mapper.map);
The preblem is when the list is in another object, for example User and UserDTO:
class User {
public List<Customer> Customers { get; set; }
}
class UserDTO {
public IEnumerable<CustomerDTO> Customers { get; set; }
}
It seems that EmitMapper does not support conversion from List to Enumerable. A way to support it would be:
var customerMapper = ObjectMapperManager
.DefaultInstance.GetMapper<Customer, CustomerDTO>();
var mapper = ObjectMapperManager.DefaultInstance
.GetMapper<User, UserDTO>(
new DefaultMapConfig()
.ConvertUsing<List<Customer>, IEnumerable<CustomerDTO>>(
a => a.Select(customerMapper.Map))
);
This can be done creating a custom class, implementing the interface "ICustomConverterProvider" and adding a ConvertGeneric to the "DefaultMapConfig".
Looking on the source code of EmitMapper, i found a class named "ArraysConverterProvider", which is the default generic converter from ICollections to Arrays.
Adapting the code from this class to work with IEnumerable collections:
class GenericIEnumerableConverterProvider : ICustomConverterProvider
{
public CustomConverterDescriptor GetCustomConverterDescr(
Type from,
Type to,
MapConfigBaseImpl mappingConfig)
{
var tFromTypeArgs = DefaultCustomConverterProvider.GetGenericArguments(from);
var tToTypeArgs = DefaultCustomConverterProvider.GetGenericArguments(to);
if (tFromTypeArgs == null || tToTypeArgs == null || tFromTypeArgs.Length != 1 || tToTypeArgs.Length != 1)
{
return null;
}
var tFrom = tFromTypeArgs[0];
var tTo = tToTypeArgs[0];
if (tFrom == tTo && (tFrom.IsValueType || mappingConfig.GetRootMappingOperation(tFrom, tTo).ShallowCopy))
{
return new CustomConverterDescriptor
{
ConversionMethodName = "Convert",
ConverterImplementation = typeof(GenericIEnumerableConverter_OneTypes<>),
ConverterClassTypeArguments = new[] { tFrom }
};
}
return new CustomConverterDescriptor
{
ConversionMethodName = "Convert",
ConverterImplementation = typeof(GenericIEnumerableConverter_DifferentTypes<,>),
ConverterClassTypeArguments = new[] { tFrom, tTo }
};
}
}
class GenericIEnumerableConverter_DifferentTypes<TFrom, TTo> : ICustomConverter
{
private Func<TFrom, TTo> _converter;
public IEnumerable<TTo> Convert(IEnumerable<TFrom> from, object state)
{
if (from == null)
{
return null;
}
TTo[] result = new TTo[from.Count()];
int idx = 0;
foreach (var f in from)
{
result[idx++] = _converter(f);
}
return result;
}
public void Initialize(Type from, Type to, MapConfigBaseImpl mappingConfig)
{
var staticConverters = mappingConfig.GetStaticConvertersManager() ?? StaticConvertersManager.DefaultInstance;
var staticConverterMethod = staticConverters.GetStaticConverter(typeof(TFrom), typeof(TTo));
if (staticConverterMethod != null)
{
_converter = (Func<TFrom, TTo>)Delegate.CreateDelegate(
typeof(Func<TFrom, TTo>),
null,
staticConverterMethod
);
}
else
{
_subMapper = ObjectMapperManager.DefaultInstance.GetMapperImpl(typeof(TFrom), typeof(TTo), mappingConfig);
_converter = ConverterBySubmapper;
}
}
ObjectsMapperBaseImpl _subMapper;
private TTo ConverterBySubmapper(TFrom from)
{
return (TTo)_subMapper.Map(from);
}
}
class GenericIEnumerableConverter_OneTypes<T>
{
public IEnumerable<T> Convert(IEnumerable<T> from, object state)
{
if (from == null)
{
return null;
}
return from;
}
}
This code is just a copy with a minimum of adaptation as possible and can be applyed to objects with many levels of hierarchy.
You can use the above code with the following command:
new DefaultMapConfig().ConvertGeneric(
typeof(IEnumerable<>),
typeof(IEnumerable<>),
new GenericIEnumerableConverterProvider());
This saved my day and I hope to save yours too! hehehe

Resources