আমি একই সমস্যার মুখোমুখি হয়েছি এবং আমি স্বতঃপ্রকাশের ত্রুটিটিকে তার ধরণের কাজটিকে অবহেলা করার জন্য জসনসেটিংকে ব্যবহার করার চেষ্টা করেছি যতক্ষণ না আমি এমন একটি ক্লাস পেয়ে যাই যা স্ব-রেফারেন্সিং খুব গভীরভাবে হয় এবং আমার ডট-নেট প্রক্রিয়াটি জসন রাইটিংয়ের মূল্যতে ঝুলে থাকে।
আমার সমস্যা
public partial class Company : BaseModel
{
public Company()
{
CompanyUsers = new HashSet<CompanyUser>();
}
public string Name { get; set; }
public virtual ICollection<CompanyUser> CompanyUsers { get; set; }
}
public partial class CompanyUser
{
public int Id { get; set; }
public int CompanyId { get; set; }
public int UserId { get; set; }
public virtual Company Company { get; set; }
public virtual User User { get; set; }
}
public partial class User : BaseModel
{
public User()
{
CompanyUsers = new HashSet<CompanyUser>();
}
public string DisplayName { get; set; }
public virtual ICollection<CompanyUser> CompanyUsers { get; set; }
}
আপনি ব্যবহারকারী শ্রেণিতে সমস্যাটি দেখতে পাচ্ছেন যা এটি কোম্পানির ব্যবহারকারী শ্রেণিতে রেফারেন্স করছে যা একটি স্ব-উল্লেখযোগ্য।
এখন, আমি getAll পদ্ধতিতে কল করছি যার মধ্যে সমস্ত সম্পর্কিত বৈশিষ্ট্য রয়েছে।
cs.GetAll("CompanyUsers", "CompanyUsers.User");
এই পর্যায়ে আমার ডটনেটকোর প্রক্রিয়াটি জেসনআরসাল্ট এক্সিকিউট করা, লেখার মান ... এবং কখনই আসে না hang আমার স্টার্টআপ.সে, আমি ইতিমধ্যে জসনঅপশন সেট করেছি set কোনও কারণে ইএফসিওরে নেস্টেড সম্পত্তি রয়েছে যা আমি ইফকে দিতে বলছি না including
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
প্রত্যাশিত আচরণ এই হওয়া উচিত
আরে এফকোর আপনি দয়া করে আমার কোম্পানির ক্লাসে "CompanyUser" ডেটা অন্তর্ভুক্ত করতে পারেন যাতে আমি সহজেই ডেটা অ্যাক্সেস করতে পারি।
তারপর
আরে এফকোর আপনি দয়া করে "CompanyUser.User" ডেটাও অন্তর্ভুক্ত করতে পারেন যাতে আমি এই কোম্পানির মতো ডেটা সহজেই অ্যাক্সেস করতে পারি
omp
এই পর্যায়ে আমি শুধু এই পাওয়া উচিত "। Company.CompanyUsers.First () User.DisplayName" এবং এটি আমাকে দিতে করা উচিত নয় Company.CompanyUsers.First () User.CompanyUsers। যা স্ব-উল্লেখ ইস্যু ঘটাচ্ছে; টেকনিক্যালি এটি আমাকে ব্যবহারকারীর দেওয়া উচিত নয় U কোম্পানির ব্যবহারকারীরা নেভিগেশনাল সম্পত্তি হিসাবে কোম্পানী ব্যবহারকারীরা। তবে, এফকোর খুব উত্সাহিত হয়ে আমাকে ইউজার.কম্পানি ইউজার দিচ্ছে ।
সুতরাং, সম্পত্তি থেকে বাদ দেওয়ার জন্য আমি একটি এক্সটেনশন পদ্ধতি লিখতে সিদ্ধান্ত নিয়েছি (এটি আসলে বাদ দিচ্ছে না এটি কেবল সম্পত্তিটি বাতিল করে দেবে)। এটি কেবল অ্যারে বৈশিষ্ট্যগুলিতেও কাজ করবে তা নয়। নীচে কোডটি আমি অন্য ব্যবহারকারীদের জন্য ন্যুগেট প্যাকেজও রফতানি করতে যাচ্ছি (এটি এমনকি কারও সাহায্য করে কিনা তা নিশ্চিত নয়)। কারণটি সহজ কারণ আমি লিখতে খুব অলস .সামান্য নির্বাচন করুন (n => নতুন {n.p1, n.p2}); আমি কেবল 1 টি সম্পত্তি বাদ দেওয়ার জন্য নির্বাচিত বিবৃতি লিখতে চাই না!
এটি হ'ল হুট করে লিখেছি এটি সেরা কোড নয় (আমি কোনও পর্যায়ে আপডেট করব) এবং যদিও এটি এমন কোনও ব্যক্তিকে সহায়তা করতে পারে যা অ্যারে দিয়ে অবজেক্টে (নাল সেট) বাদ দিতে চায়।
public static class PropertyExtensions
{
public static void Exclude<T>(this T obj, Expression<Func<T, object>> expression)
{
var visitor = new PropertyVisitor<T>();
visitor.Visit(expression.Body);
visitor.Path.Reverse();
List<MemberInfo> paths = visitor.Path;
Action<List<MemberInfo>, object> act = null;
int recursiveLevel = 0;
act = (List<MemberInfo> vPath, object vObj) =>
{
// set last propert to null thats what we want to avoid the self-referencing error.
if (recursiveLevel == vPath.Count - 1)
{
if (vObj == null) throw new ArgumentNullException("Object cannot be null");
vObj.GetType().GetMethod($"set_{vPath.ElementAt(recursiveLevel).Name}").Invoke(vObj, new object[] { null });
return;
}
var pi = vObj.GetType().GetProperty(vPath.ElementAt(recursiveLevel).Name);
if (pi == null) return;
var pv = pi.GetValue(vObj, null);
if (pi.PropertyType.IsArray || pi.PropertyType.Name.Contains("HashSet`1") || pi.PropertyType.Name.Contains("ICollection`1"))
{
var ele = (IEnumerator)pv.GetType().GetMethod("GetEnumerator").Invoke(pv, null);
while (ele.MoveNext())
{
recursiveLevel++;
var arrItem = ele.Current;
act(vPath, arrItem);
recursiveLevel--;
}
if (recursiveLevel != 0) recursiveLevel--;
return;
}
else
{
recursiveLevel++;
act(vPath, pv);
}
if (recursiveLevel != 0) recursiveLevel--;
};
// check if the root level propert is array
if (obj.GetType().IsArray)
{
var ele = (IEnumerator)obj.GetType().GetMethod("GetEnumerator").Invoke(obj, null);
while (ele.MoveNext())
{
recursiveLevel = 0;
var arrItem = ele.Current;
act(paths, arrItem);
}
}
else
{
recursiveLevel = 0;
act(paths, obj);
}
}
public static T Explode<T>(this T[] obj)
{
return obj.FirstOrDefault();
}
public static T Explode<T>(this ICollection<T> obj)
{
return obj.FirstOrDefault();
}
}
উপরের এক্সটেনশান ক্লাসটি আপনাকে স্ব-রেফারেন্সিং লুপ এমনকি অ্যারেগুলি এড়ানোর জন্য সম্পত্তিটি বাতিল করে দেওয়ার ক্ষমতা দেবে।
এক্সপ্রেশন নির্মাতা
internal class PropertyVisitor<T> : ExpressionVisitor
{
public readonly List<MemberInfo> Path = new List<MemberInfo>();
public Expression Modify(Expression expression)
{
return Visit(expression);
}
protected override Expression VisitMember(MemberExpression node)
{
if (!(node.Member is PropertyInfo))
{
throw new ArgumentException("The path can only contain properties", nameof(node));
}
Path.Add(node.Member);
return base.VisitMember(node);
}
}
রীতিনীতি:
মডেল ক্লাস
public class Person
{
public string Name { get; set; }
public Address AddressDetail { get; set; }
}
public class Address
{
public string Street { get; set; }
public Country CountryDetail { get; set; }
public Country[] CountryDetail2 { get; set; }
}
public class Country
{
public string CountryName { get; set; }
public Person[] CountryDetail { get; set; }
}
ডামি ডেটা
var p = new Person
{
Name = "Adeel Rizvi",
AddressDetail = new Address
{
Street = "Sydney",
CountryDetail = new Country
{
CountryName = "AU"
}
}
};
var p1 = new Person
{
Name = "Adeel Rizvi",
AddressDetail = new Address
{
Street = "Sydney",
CountryDetail2 = new Country[]
{
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A1" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A2" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A3" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A4" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A5" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A6" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A7" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A8" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A9" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A1" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A2" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A3" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A4" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A5" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A6" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A7" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A8" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A9" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
}
}
};
মামলা:
কেস 1: কোনও অ্যারে ছাড়াই কেবল সম্পত্তি বাদ দিন
p.Exclude(n => n.AddressDetail.CountryDetail.CountryName);
কেস 2: 1 অ্যারে দিয়ে সম্পত্তি বাদ দিন
p1.Exclude(n => n.AddressDetail.CountryDetail2.Explode().CountryName);
কেস 3: 2 নেস্টেড অ্যারে দিয়ে সম্পত্তি বাদ দিন
p1.Exclude(n => n.AddressDetail.CountryDetail2.Explode().CountryDetail.Explode().Name);
কেস ৪: অন্তর্ভুক্ত সহ ইএফ গেটএল অনুসন্ধান
var query = cs.GetAll("CompanyUsers", "CompanyUsers.User").ToArray();
query.Exclude(n => n.Explode().CompanyUsers.Explode().User.CompanyUsers);
return query;
আপনার লক্ষ্য আছে যে বিস্ফোরণ () পদ্ধতিটি এটি কেবলমাত্র আমাদের এক্সপ্রেশন বিল্ডারের অ্যারে সম্পত্তি থেকে সম্পত্তি পেতে extension যখনই কোনও অ্যারের বৈশিষ্ট্য উপস্থিত থাকে তখন .Exlode ()। YourPropertyToExclude বা। এক্সপ্লোড ()। সম্পত্তি1.MyArrayProperty.Explode ()। MyStupidProperty । উপরের কোডটি আমাকে যতটা গভীর চাই আত্ম-রেফারেন্সিং এড়াতে সহায়তা করে। এখন আমি গেটএল ব্যবহার করতে পারি এবং যে সম্পত্তিটি আমি চাই না তা বাদ দিতে পারি!
এই বড় পোস্ট পড়ার জন্য আপনাকে ধন্যবাদ!