Get item’s metadata with Entity Framework? - sharepoint

I'm working with Sharepoint 2010.
I need to know the date of creation/edition and the author/editor of items in my sharepoint's Lists, but I didn't find a solution to map these columns with Entity Framework.
I tried this kind of code :
[Microsoft.SharePoint.Linq.ColumnAttribute(Name = "tp_author", Storage = "_author", ReadOnly = true, FieldType = "User")]
public SPUser Author
{
get
{
return this._author;
}
set
{
if (!value.Equals(this._author))
{
this.OnPropertyChanging("Author", this._author);
this._author = value;
this.OnPropertyChanged("Author");
}
}
}
But with that code, Sharepoint give me this error:
Invalid transfer type Microsoft.SharePoint.SPUser
I also tried with other types for _author, but it doesn't change anything.
Is there a way to make this mapping?

SPMetal generates the following code for a user field
[Microsoft.SharePoint.Linq.ColumnAttribute(Name="AssignedTo", Storage="_assignedToId", FieldType="User", IsLookupId=true)]
public System.Nullable<int> AssignedToId {
get {
return this._assignedToId;
}
set {
if ((value != this._assignedToId)) {
this.OnPropertyChanging("AssignedToId", this._assignedToId);
this._assignedToId = value;
this.OnPropertyChanged("AssignedToId");
}
}
}
[Microsoft.SharePoint.Linq.ColumnAttribute(Name="AssignedTo", Storage="_assignedTo", ReadOnly=true, FieldType="User", IsLookupValue=true)]
public string AssignedTo {
get {
return this._assignedTo;
}
set {
if ((value != this._assignedTo)) {
this.OnPropertyChanging("AssignedTo", this._assignedTo);
this._assignedTo = value;
this.OnPropertyChanged("AssignedTo");
}
}
}

Related

Could haxe macro be used to detect when object is dirty (any property has been changed)

Let say we have an object:
#:checkDirty
class Test {
var a:Int;
var b(default, default):String;
var c(get, set):Array<Int>;
public function new() {
...
}
public function get_c() {
...
}
public function set_c(n) {
...
}
}
Could we write a macro checkDirty so that any change to field/properties would set property dirty to true. Macro would generate dirty field as Bool and clearDirty function to set it to false.
var test = new Test();
trace(test.dirty); // false
test.a = 12;
trace(test.dirty); // true
test.clearDirty();
trace(test.dirty); //false
test.b = "test"
trace(test.dirty); //true
test.clearDirty();
test.c = [1,2,3];
trace(test.dirty); //true
Just to note - whenever you consider proxying access to an object, in my experience, there are always hidden costs / added complexity. :)
That said, you have a few approaches:
First, if you want it to be pure Haxe, then either a macro or an abstract can get the job done. Either way, you're effectively transforming every property access into a function call that sets the value and also sets dirty.
For example, an abstract using the #:resolve getter and setter can be found in the NME source code, replicated here for convenience:
#:forward(decode,toString)
abstract URLVariables(URLVariablesBase)
{
public function new(?inEncoded:String)
{
this = new URLVariablesBase(inEncoded);
}
#:resolve
public function set(name:String, value:String) : String
{
return this.set(name,value);
}
#:resolve
public function get(name:String):String
{
return this.get(name);
}
}
This may be an older syntax, I'm not sure... also look at the operator overloading examples on the Haxe manual:
#:op(a.b) public function fieldRead(name:String)
return this.indexOf(name);
#:op(a.b) public function fieldWrite(name:String, value:String)
return this.split(name).join(value);
Second, I'd just point out that if the underlying language / runtime supports some kind of Proxy object (e.g. JavaScript Proxy), and macro / abstract isn't working as expected, then you could build your functionality on top of that.
I wrote a post (archive) about doing this kind of thing (except for emitting events) before - you can use a #:build macro to modify class members, be it appending an extra assignment into setter or replacing the field with a property.
So a modified version might look like so:
class Macro {
public static macro function build():Array<Field> {
var fields = Context.getBuildFields();
for (field in fields.copy()) { // (copy fields so that we don't go over freshly added ones)
switch (field.kind) {
case FVar(fieldType, fieldExpr), FProp("default", "default", fieldType, fieldExpr):
var fieldName = field.name;
if (fieldName == "dirty") continue;
var setterName = "set_" + fieldName;
var tmp_class = macro class {
public var $fieldName(default, set):$fieldType = $fieldExpr;
public function $setterName(v:$fieldType):$fieldType {
$i{fieldName} = v;
this.dirty = true;
return v;
}
};
for (mcf in tmp_class.fields) fields.push(mcf);
fields.remove(field);
case FProp(_, "set", t, e):
var setter = Lambda.find(fields, (f) -> f.name == "set_" + field.name);
if (setter == null) continue;
switch (setter.kind) {
case FFun(f):
f.expr = macro { dirty = true; ${f.expr}; };
default:
}
default:
}
}
if (Lambda.find(fields, (f) -> f.name == "dirty") == null) fields.push((macro class {
public var dirty:Bool = false;
}).fields[0]);
return fields;
}
}
which, if used as
#:build(Macro.build())
#:keep class Some {
public function new() {}
public var one:Int;
public var two(default, set):String;
function set_two(v:String):String {
two = v;
return v;
}
}
Would emit the following JS:
var Some = function() {
this.dirty = false;
};
Some.prototype = {
set_two: function(v) {
this.dirty = true;
this.two = v;
return v;
}
,set_one: function(v) {
this.one = v;
this.dirty = true;
return v;
}
};

Using CoreData Objects in a List as Environment Object

I'm currently creating a News-Feed-Reader App with SwiftUI.
I'm fetching the feed-items and storing them in CoreData
I'd like to display the objects in a List containing NavigationLinks to a Detail View and automatically mark them as read when clicking on them.
I'm currently fetching the objects and putting them in a ObservableObject.
This is the ObservableObject class:
final class FeedItem: ObservableObject, Hashable {
static func == (lhs: FeedItem, rhs: FeedItem) -> Bool {
return lhs.item.pubDate == rhs.item.pubDate && lhs.item.articleUrl == rhs.item.articleUrl
}
func hash(into hasher: inout Hasher) {
hasher.combine(item.articleUrl)
}
let objectWillChange = PassthroughSubject<Void, Never>()
init(item: NewsItem) {
self.item = item
}
// NewsItem is the Managed Object
var item: NewsItem
var bookmarked: Bool {
set {
//This function fetches the Object and marks it as bookmarked
DatabaseManager().markAs(item: item, .read, newValue)
self.item.bookmarked = newValue
}
get {
self.item.bookmarked
}
}
var read: Bool {
set {
//This function fetches the Object and marks it as read
DatabaseManager().markAs(item: item, .read, newValue)
self.item.read = newValue
}
get {
self.item.read
}
}
}
In the moment Im creating an environment Object (EO) containing an array of all ObservableObjects
This EO is passed down to the list and whenever Im clicking on an item Im setting its read value to true thereby changing the Core Data Object.
This is the list:
#EnvironmentObject var feed: // THe array of ObservableObjects
List() {
ForEach(feed.items.indices, id:\.self) { i in
Button(action: {
self.feed.items[i].read = true
self.selectedItem = i
self.showDetail = true
}) {
ListFeedItem(item: self.$feed.items[i])
}
}
}
This method is quite slow. Whenever I'm opening the Detail View and going back a few seconds later the List-Item takes multiple seconds to refresh.
Any ideas on how I could improve this?

How to return top previous URL after Edit in ASP.NET Core

I am using asp,net core and have used the tutorial to create sorted, paged and search page (Index). Once I edit an item from this page the controller always dumps me back to the default index page. How do I return to the previous URL. Many thanks.
Here is a section of my controller file.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, Bind("id,UserPassword,user")] UserProfiles userProfiles)
{
var users = from u in _context.UserProfiles
select u;
if (id != userProfiles.id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(userProfiles);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!UserProfilesExists(userProfiles.id))
{
return NotFound();
}
else
{
throw;
}
}
// ***************
// Redirect to the previous URL,i.e. the Index
return Redirect(TempData["PreviousURL"].ToString()) ;
}
return View(userProfiles);
}
public async Task<IActionResult> Index(string sortOrder, string currentFilter, string searchString, int? page)
{
ViewData["CurrentSort"] = sortOrder;
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
// paging
if (searchString != null)
{
page = 1;
}
else
{
searchString = currentFilter;
}
// search
ViewData["CurrentFilter"] = searchString;
var users = from u in _context.UserProfiles
select u;
if (!String.IsNullOrEmpty(searchString))
{
users = users.Where(u => u.user.Contains(searchString)
);
}
//sort
switch (sortOrder)
{
case "name_desc":
users = users.OrderByDescending(u => u.user);
break;
default:
users = users.OrderBy(s => s.user);
break;
}
// ***************
// store the current path and query string in TempData["PreviousURL" session variable
TempData["PreviousURL"] = HttpContext.Request.Path.ToString() + HttpContext.Request.QueryString.ToString();
return View(await PaginatedList<UserProfiles>.CreateAsync(users.AsNoTracking(), page ?? 1, pageSize));
}
This is my first MVC project.
It depends on your logic where controller takes you after saving data.
You need to pass search, sort and paging related data to controller when saving data. You can send them as part of extra post data, as query string parameters or as part of the model itself which is being posted.
After saving data retrieve data based on those parameters and populater your view with that paged, filtred and sorted data.
I solved my problem with the use of session variables: ViewData, ViewBag and TempData. The following two pages were very useful:
https://www.codeproject.com/Articles/476967/What-is-ViewData-ViewBag-and-TempData-MVC-Option
http://andrewlock.net/an-introduction-to-session-storage-in-asp-net-core/
Please see edited question above for the solution.

CRM 2011 development: Get the following error if I try to get related entity: Object reference not set to an instance of an object

I try to get a related entity and get this error: Object reference not set to an instance of an object.
See below my code:
public IEnumerable<RUBAnnotation> GetAnnotationsByServiceRequestId(string serviceRequestId)
{
List<Annotation> annotationList = new List<Annotation>();
try
{
using (OrganizationServiceProxy organizationProxy = new OrganizationServiceProxy(organisationWebServiceUri, null, userCredentials, deviceCredentials))
{
organizationProxy.EnableProxyTypes();
var service = (IOrganizationService)organizationProxy;
OrganizationServiceContext orgContext = new OrganizationServiceContext(service);
Relationship rel = new Relationship("Incident_Annotation");
// get all incidents by incidentId
IEnumerable<Incident> incidents = from c in orgContext.CreateQuery<Incident>()
where c.Id == new Guid(serviceRequestId)
select c;
return GetAnnotationsEntities(incidents);
}
}
catch (Exception)
{
throw;
}
return null;
}
private List<RUBAnnotation> GetAnnotationsEntities(IEnumerable<Incident> incidents)
{
List<RUBAnnotation> annotationsList = new List<RUBAnnotation>();
try
{
foreach (Incident incident in incidents)
{
foreach (var annotation in incident.Incident_Annotation) // HERE OCCURS THE EXCEPTION!!
{
if (!string.IsNullOrEmpty(annotation.NoteText))
{
var customAnnotation = new RUBAnnotation();
customAnnotation.Id = annotation.Id.ToString();
if (annotation.Incident_Annotation != null)
{
customAnnotation.ServiceRequestId = annotation.Incident_Annotation.Id.ToString();
}
customAnnotation.Message = annotation.NoteText;
customAnnotation.CreatedOn = (DateTime)annotation.CreatedOn;
customAnnotation.UserId = annotation.CreatedBy.Id.ToString();
annotationsList.Add(customAnnotation);
}
}
}
}
catch (Exception e)
{
throw e;
}
return annotationsList;
}
Why do I get this error when I try to get incident.Incident_Annotation ? I think incident.Incident_Annotation is NULL, but why? Al my incidents have minimal 1 or more annotations.
Related entities must be explicitly loaded, you can find more information on this MSDN article:
MSDN - Access Entity Relationships

Casting on run time using implicit con version

I have the following code which copies property values from one object to another objects by matching their property names:
public static void CopyProperties(object source, object target,bool caseSenstive=true)
{
PropertyInfo[] targetProperties = target.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
PropertyInfo[] sourceProperties = source.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo tp in targetProperties)
{
var sourceProperty = sourceProperties.FirstOrDefault(p => p.Name == tp.Name);
if (sourceProperty == null && !caseSenstive)
{
sourceProperty = sourceProperties.FirstOrDefault(p => p.Name.ToUpper() == tp.Name.ToUpper());
}
// If source doesn't have this property, go for next one.
if(sourceProperty ==null)
{
continue;
}
// If target property is not writable then we can not set it;
// If source property is not readable then cannot check it's value
if (!tp.CanWrite || !sourceProperty.CanRead)
{
continue;
}
MethodInfo mget = sourceProperty.GetGetMethod(false);
MethodInfo mset = tp.GetSetMethod(false);
// Get and set methods have to be public
if (mget == null)
{
continue;
}
if (mset == null)
{
continue;
}
var sourcevalue = sourceProperty.GetValue(source, null);
tp.SetValue(target, sourcevalue, null);
}
}
This is working well when the type of properties on target and source are the same. But when there is a need for casting, the code doesn't work.
For example, I have the following object:
class MyDateTime
{
public static implicit operator DateTime?(MyDateTime myDateTime)
{
return myDateTime.DateTime;
}
public static implicit operator DateTime(MyDateTime myDateTime)
{
if (myDateTime.DateTime.HasValue)
{
return myDateTime.DateTime.Value;
}
else
{
return System.DateTime.MinValue;
}
}
public static implicit operator MyDateTime(DateTime? dateTime)
{
return FromDateTime(dateTime);
}
public static implicit operator MyDateTime(DateTime dateTime)
{
return FromDateTime(dateTime);
}
}
If I do the following, the implicit cast is called and everything works well:
MyDateTime x= DateTime.Now;
But when I have a two objects that one of them has a DateTime and the other has MyDateTime, and I am using the above code to copy properties from one object to other, it doesn't and generate an error saying that DateTime can not converted to MyTimeDate.
How can I fix this problem?
One ghastly approach which should work is to mix dynamic and reflection:
private static T ConvertValue<T>(dynamic value)
{
return value; // This will perform conversion automatically
}
Then:
var sourceValue = sourceProperty.GetValue(source, null);
if (sourceProperty.PropertyType != tp.PropertyType)
{
var method = typeof(PropertyCopier).GetMethod("ConvertValue",
BindingFlags.Static | BindingFlags.NonPublic);
method = method.MakeGenericMethod(new[] { tp.PropertyType };
sourceValue = method.Invoke(null, new[] { sourceValue });
}
tp.SetValue(target, sourceValue, null);
We need to use reflection to invoke the generic method with the right type argument, but dynamic typing will use the right conversion operator for you.
Oh, and one final request: please don't include my name anywhere near this code, whether it's in comments, commit logs. Aargh.

Resources